Lely core libraries  2.2.5
device.cpp
Go to the documentation of this file.
1 
24 #include "coapp.hpp"
25 #include <lely/coapp/device.hpp>
26 #include <lely/util/error.hpp>
27 
28 #include <lely/co/csdo.hpp>
29 #include <lely/co/dcf.hpp>
30 #include <lely/co/obj.hpp>
31 #include <lely/co/pdo.h>
32 
33 #include <map>
34 #include <string>
35 #include <tuple>
36 #include <utility>
37 #include <vector>
38 
39 namespace lely {
40 
41 namespace canopen {
42 
45  Impl_(Device* self, const ::std::string& dcf_txt,
46  const ::std::string& dcf_bin, uint8_t id, util::BasicLockable* mutex);
47  virtual ~Impl_() = default;
48 
49  void
50  lock() override {
51  if (mutex) mutex->lock();
52  }
53 
54  void
55  unlock() override {
56  if (mutex) mutex->unlock();
57  }
58 
59  uint8_t
60  netid() const noexcept {
61  return dev->getNetid();
62  }
63 
64  uint8_t
65  id() const noexcept {
66  return dev->getId();
67  }
68 
69  void Set(uint16_t idx, uint8_t subidx, const ::std::string& value,
70  ::std::error_code& ec) noexcept;
71 
72  void Set(uint16_t idx, uint8_t subidx, const ::std::vector<uint8_t>& value,
73  ::std::error_code& ec) noexcept;
74 
75  void Set(uint16_t idx, uint8_t subidx,
76  const ::std::basic_string<char16_t>& value,
77  ::std::error_code& ec) noexcept;
78 
79  template <uint16_t N>
80  void Set(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n,
81  ::std::error_code& ec) noexcept;
82 
83  void OnWrite(uint16_t idx, uint8_t subidx);
84 
85  ::std::tuple<uint16_t, uint8_t>
86  RpdoMapping(uint8_t id, uint16_t idx, uint8_t subidx,
87  ::std::error_code& ec) const noexcept {
88  auto it = rpdo_mapping.find((static_cast<uint32_t>(id) << 24) |
89  (static_cast<uint32_t>(idx) << 8) | subidx);
90  if (it != rpdo_mapping.end()) {
91  idx = (it->second >> 8) & 0xffff;
92  subidx = it->second & 0xff;
93  } else {
94  ec = SdoErrc::NO_PDO;
95  idx = 0;
96  subidx = 0;
97  }
98  return ::std::make_tuple(idx, subidx);
99  }
100 
101  ::std::tuple<uint8_t, uint16_t, uint8_t>
102  RpdoMapping(uint16_t idx, uint8_t subidx, ::std::error_code& ec) const
103  noexcept {
104  uint8_t id = 0;
105  auto it = rpdo_mapping.find((static_cast<uint32_t>(idx) << 8) | subidx);
106  if (it != rpdo_mapping.end()) {
107  id = (it->second >> 24) & 0xff;
108  idx = (it->second >> 8) & 0xffff;
109  subidx = it->second & 0xff;
110  } else {
111  ec = SdoErrc::NO_PDO;
112  idx = 0;
113  subidx = 0;
114  }
115  return ::std::make_tuple(id, idx, subidx);
116  }
117 
118  ::std::tuple<uint16_t, uint8_t>
119  TpdoMapping(uint8_t id, uint16_t idx, uint8_t subidx,
120  ::std::error_code& ec) const noexcept {
121  auto it = tpdo_mapping.find((static_cast<uint32_t>(id) << 24) |
122  (static_cast<uint32_t>(idx) << 8) | subidx);
123  if (it != tpdo_mapping.end()) {
124  idx = (it->second >> 8) & 0xffff;
125  subidx = it->second & 0xff;
126  } else {
127  ec = SdoErrc::NO_PDO;
128  idx = 0;
129  subidx = 0;
130  }
131  return ::std::make_tuple(idx, subidx);
132  }
133 
134  Device* self;
135 
136  BasicLockable* mutex{nullptr};
137 
138  unique_c_ptr<CODev> dev;
139 
140  ::std::map<uint32_t, uint32_t> rpdo_mapping;
141  ::std::map<uint32_t, uint32_t> tpdo_mapping;
142 
143  ::std::function<void(uint16_t, uint8_t)> on_write;
144  ::std::function<void(uint8_t, uint16_t, uint8_t)> on_rpdo_write;
145 };
146 
147 Device::Device(const ::std::string& dcf_txt, const ::std::string& dcf_bin,
148  uint8_t id, util::BasicLockable* mutex)
149  : impl_(new Impl_(this, dcf_txt, dcf_bin, id, mutex)) {}
150 
151 Device::~Device() = default;
152 
153 uint8_t
154 Device::netid() const noexcept {
155  ::std::lock_guard<Impl_> lock(*impl_);
156 
157  return impl_->netid();
158 }
159 
160 uint8_t
161 Device::id() const noexcept {
162  ::std::lock_guard<Impl_> lock(*impl_);
163 
164  return impl_->id();
165 }
166 
167 namespace {
168 
169 void
170 OnDnCon(COCSDO*, uint16_t, uint8_t, uint32_t ac, void* data) noexcept {
171  *static_cast<uint32_t*>(data) = ac;
172 }
173 
174 template <class T>
175 void
176 OnUpCon(COCSDO*, uint16_t, uint8_t, uint32_t ac, T value, void* data) noexcept {
177  auto* t = static_cast<decltype(::std::tie(ac, value))*>(data);
178  *t = ::std::forward_as_tuple(ac, ::std::move(value));
179 }
180 
181 } // namespace
182 
183 template <class T>
184 typename ::std::enable_if<detail::is_canopen_type<T>::value, T>::type
185 Device::Read(uint16_t idx, uint8_t subidx) const {
186  ::std::error_code ec;
187  T value(Read<T>(idx, subidx, ec));
188  if (ec) throw_sdo_error(id(), idx, subidx, ec, "Read");
189  return value;
190 }
191 
192 template <class T>
193 typename ::std::enable_if<detail::is_canopen_type<T>::value, T>::type
194 Device::Read(uint16_t idx, uint8_t subidx, ::std::error_code& ec) const {
195  uint32_t ac = 0;
196  T value = T();
197  auto t = ::std::tie(ac, value);
198 
199  ::std::lock_guard<Impl_> lock(*impl_);
200  int errsv = get_errc();
201  set_errc(0);
202  if (!upReq<T, &OnUpCon<T>>(*impl_->dev, idx, subidx, &t)) {
203  if (ac)
204  ec = static_cast<SdoErrc>(ac);
205  else
206  ec.clear();
207  } else {
208  ec = util::make_error_code();
209  }
210  set_errc(errsv);
211  return value;
212 }
213 
214 template <class T>
215 typename ::std::enable_if<detail::is_canopen_basic<T>::value>::type
216 Device::Write(uint16_t idx, uint8_t subidx, T value) {
217  ::std::error_code ec;
218  Write(idx, subidx, value, ec);
219  if (ec) throw_sdo_error(id(), idx, subidx, ec, "Write");
220 }
221 
222 template <class T>
223 typename ::std::enable_if<detail::is_canopen_basic<T>::value>::type
224 Device::Write(uint16_t idx, uint8_t subidx, T value, ::std::error_code& ec) {
225  constexpr auto N = co_type_traits_T<T>::index;
226  uint32_t ac = 0;
227 
228  ::std::lock_guard<Impl_> lock(*impl_);
229  int errsv = get_errc();
230  set_errc(0);
231  if (!dnReq<N>(*impl_->dev, idx, subidx, value, &OnDnCon, &ac)) {
232  if (ac)
233  ec = static_cast<SdoErrc>(ac);
234  else
235  ec.clear();
236  } else {
237  ec = util::make_error_code();
238  }
239  set_errc(errsv);
240 }
241 
242 template <class T>
243 typename ::std::enable_if<detail::is_canopen_array<T>::value>::type
244 Device::Write(uint16_t idx, uint8_t subidx, const T& value) {
245  ::std::error_code ec;
246  Write(idx, subidx, value, ec);
247  if (ec) throw_sdo_error(id(), idx, subidx, ec, "Write");
248 }
249 
250 template <class T>
251 typename ::std::enable_if<detail::is_canopen_array<T>::value>::type
252 Device::Write(uint16_t idx, uint8_t subidx, const T& value,
253  ::std::error_code& ec) {
254  constexpr auto N = co_type_traits_T<T>::index;
255  uint32_t ac = 0;
256 
257  ::std::lock_guard<Impl_> lock(*impl_);
258  int errsv = get_errc();
259  set_errc(0);
260  if (!dnReq<N>(*impl_->dev, idx, subidx, value, &OnDnCon, &ac)) {
261  if (ac)
262  ec = static_cast<SdoErrc>(ac);
263  else
264  ec.clear();
265  } else {
266  ec = util::make_error_code();
267  }
268  set_errc(errsv);
269 }
270 
271 #ifndef DOXYGEN_SHOULD_SKIP_THIS
272 
273 // BOOLEAN
274 template bool Device::Read<bool>(uint16_t, uint8_t) const;
275 template bool Device::Read<bool>(uint16_t, uint8_t, ::std::error_code&) const;
276 template void Device::Write<bool>(uint16_t, uint8_t, bool);
277 template void Device::Write<bool>(uint16_t, uint8_t, bool, ::std::error_code&);
278 
279 // INTEGER8
280 template int8_t Device::Read<int8_t>(uint16_t, uint8_t) const;
281 template int8_t Device::Read<int8_t>(uint16_t, uint8_t,
282  ::std::error_code&) const;
283 template void Device::Write<int8_t>(uint16_t, uint8_t, int8_t);
284 template void Device::Write<int8_t>(uint16_t, uint8_t, int8_t,
285  ::std::error_code&);
286 
287 // INTEGER16
288 template int16_t Device::Read<int16_t>(uint16_t, uint8_t) const;
289 template int16_t Device::Read<int16_t>(uint16_t, uint8_t,
290  ::std::error_code&) const;
291 template void Device::Write<int16_t>(uint16_t, uint8_t, int16_t);
292 template void Device::Write<int16_t>(uint16_t, uint8_t, int16_t,
293  ::std::error_code&);
294 
295 // INTEGER32
296 template int32_t Device::Read<int32_t>(uint16_t, uint8_t) const;
297 template int32_t Device::Read<int32_t>(uint16_t, uint8_t,
298  ::std::error_code&) const;
299 template void Device::Write<int32_t>(uint16_t, uint8_t, int32_t);
300 template void Device::Write<int32_t>(uint16_t, uint8_t, int32_t,
301  ::std::error_code&);
302 
303 // UNSIGNED8
304 template uint8_t Device::Read<uint8_t>(uint16_t, uint8_t) const;
305 template uint8_t Device::Read<uint8_t>(uint16_t, uint8_t,
306  ::std::error_code&) const;
307 template void Device::Write<uint8_t>(uint16_t, uint8_t, uint8_t);
308 template void Device::Write<uint8_t>(uint16_t, uint8_t, uint8_t,
309  ::std::error_code&);
310 
311 // UNSIGNED16
312 template uint16_t Device::Read<uint16_t>(uint16_t, uint8_t) const;
313 template uint16_t Device::Read<uint16_t>(uint16_t, uint8_t,
314  ::std::error_code&) const;
315 template void Device::Write<uint16_t>(uint16_t, uint8_t, uint16_t);
316 template void Device::Write<uint16_t>(uint16_t, uint8_t, uint16_t,
317  ::std::error_code&);
318 
319 // UNSIGNED32
320 template uint32_t Device::Read<uint32_t>(uint16_t, uint8_t) const;
321 template uint32_t Device::Read<uint32_t>(uint16_t, uint8_t,
322  ::std::error_code&) const;
323 template void Device::Write<uint32_t>(uint16_t, uint8_t, uint32_t);
324 template void Device::Write<uint32_t>(uint16_t, uint8_t, uint32_t,
325  ::std::error_code&);
326 
327 // REAL32
328 template float Device::Read<float>(uint16_t, uint8_t) const;
329 template float Device::Read<float>(uint16_t, uint8_t, ::std::error_code&) const;
330 template void Device::Write<float>(uint16_t, uint8_t, float);
331 template void Device::Write<float>(uint16_t, uint8_t, float,
332  ::std::error_code&);
333 
334 // VISIBLE_STRING
335 template ::std::string Device::Read<::std::string>(uint16_t, uint8_t) const;
336 template ::std::string Device::Read<::std::string>(uint16_t, uint8_t,
337  ::std::error_code&) const;
338 template void Device::Write<::std::string>(uint16_t, uint8_t,
339  const ::std::string&);
340 template void Device::Write<::std::string>(uint16_t, uint8_t,
341  const ::std::string&,
342  ::std::error_code&);
343 
344 // OCTET_STRING
345 template ::std::vector<uint8_t> Device::Read<::std::vector<uint8_t>>(
346  uint16_t, uint8_t) const;
347 template ::std::vector<uint8_t> Device::Read<::std::vector<uint8_t>>(
348  uint16_t, uint8_t, ::std::error_code&) const;
349 template void Device::Write<::std::vector<uint8_t>>(
350  uint16_t, uint8_t, const ::std::vector<uint8_t>&);
351 template void Device::Write<::std::vector<uint8_t>>(
352  uint16_t, uint8_t, const ::std::vector<uint8_t>&, ::std::error_code&);
353 
354 // UNICODE_STRING
355 template ::std::basic_string<char16_t>
356  Device::Read<::std::basic_string<char16_t>>(uint16_t, uint8_t) const;
357 template ::std::basic_string<char16_t>
358 Device::Read<::std::basic_string<char16_t>>(uint16_t, uint8_t,
359  ::std::error_code&) const;
360 template void Device::Write<::std::basic_string<char16_t>>(
361  uint16_t, uint8_t, const ::std::basic_string<char16_t>&);
362 template void Device::Write<::std::basic_string<char16_t>>(
363  uint16_t, uint8_t, const ::std::basic_string<char16_t>&,
364  ::std::error_code&);
365 
366 // TIME_OF_DAY
367 // TIME_DIFFERENCE
368 // DOMAIN
369 // INTEGER24
370 
371 // REAL64
372 template double Device::Read<double>(uint16_t, uint8_t) const;
373 template double Device::Read<double>(uint16_t, uint8_t,
374  ::std::error_code&) const;
375 template void Device::Write<double>(uint16_t, uint8_t, double);
376 template void Device::Write<double>(uint16_t, uint8_t, double,
377  ::std::error_code&);
378 
379 // INTEGER40
380 // INTEGER48
381 // INTEGER56
382 
383 // INTEGER64
384 template int64_t Device::Read<int64_t>(uint16_t, uint8_t) const;
385 template int64_t Device::Read<int64_t>(uint16_t, uint8_t,
386  ::std::error_code&) const;
387 template void Device::Write<int64_t>(uint16_t, uint8_t, int64_t);
388 template void Device::Write<int64_t>(uint16_t, uint8_t, int64_t,
389  ::std::error_code&);
390 
391 // UNSIGNED24
392 // UNSIGNED40
393 // UNSIGNED48
394 // UNSIGNED56
395 
396 // UNSIGNED64
397 template uint64_t Device::Read<uint64_t>(uint16_t, uint8_t) const;
398 template uint64_t Device::Read<uint64_t>(uint16_t, uint8_t,
399  ::std::error_code&) const;
400 template void Device::Write<uint64_t>(uint16_t, uint8_t, uint64_t);
401 template void Device::Write<uint64_t>(uint16_t, uint8_t, uint64_t,
402  ::std::error_code&);
403 
404 #endif // DOXYGEN_SHOULD_SKIP_THIS
405 
406 void
407 Device::Write(uint16_t idx, uint8_t subidx, const char* value) {
408  ::std::error_code ec;
409  Write(idx, subidx, value, ec);
410  if (ec) throw_sdo_error(id(), idx, subidx, ec, "Write");
411 }
412 
413 void
414 Device::Write(uint16_t idx, uint8_t subidx, const char* value,
415  ::std::error_code& ec) {
416  Write(idx, subidx, value, ::std::char_traits<char>::length(value), ec);
417 }
418 
419 void
420 Device::Write(uint16_t idx, uint8_t subidx, const char16_t* value) {
421  ::std::error_code ec;
422  Write(idx, subidx, value, ec);
423  if (ec) throw_sdo_error(id(), idx, subidx, ec, "Write");
424 }
425 
426 void
427 Device::Write(uint16_t idx, uint8_t subidx, const char16_t* value,
428  ::std::error_code& ec) {
429  constexpr auto N = CO_DEFTYPE_UNICODE_STRING;
430  uint32_t ac = 0;
431 
432  ::std::lock_guard<Impl_> lock(*impl_);
433  int errsv = get_errc();
434  set_errc(0);
435  // TODO(jseldenthuis@lely.com): Prevent unnecessary copy.
436  if (!dnReq<N>(*impl_->dev, idx, subidx, value, &OnDnCon, &ac)) {
437  if (ac)
438  ec = static_cast<SdoErrc>(ac);
439  else
440  ec.clear();
441  } else {
442  ec = util::make_error_code();
443  }
444  set_errc(errsv);
445 }
446 
447 void
448 Device::Write(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n) {
449  ::std::error_code ec;
450  Write(idx, subidx, p, n, ec);
451  if (ec) throw_sdo_error(id(), idx, subidx, ec, "Write");
452 }
453 
454 void
455 Device::Write(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n,
456  ::std::error_code& ec) {
457  uint32_t ac = 0;
458 
459  ::std::lock_guard<Impl_> lock(*impl_);
460  int errsv = get_errc();
461  set_errc(0);
462  if (!dnReq(*impl_->dev, idx, subidx, p, n, &OnDnCon, &ac)) {
463  if (ac)
464  ec = static_cast<SdoErrc>(ac);
465  else
466  ec.clear();
467  } else {
468  ec = util::make_error_code();
469  }
470  set_errc(errsv);
471 }
472 
473 void
474 Device::WriteEvent(uint16_t idx, uint8_t subidx) {
475  ::std::error_code ec;
476  WriteEvent(idx, subidx, ec);
477  if (ec) throw_sdo_error(id(), idx, subidx, ec, "WriteEvent");
478 }
479 
480 void
481 Device::WriteEvent(uint16_t idx, uint8_t subidx,
482  ::std::error_code& ec) noexcept {
483  ::std::lock_guard<Impl_> lock(*impl_);
484 
485  SetEvent(idx, subidx, ec);
486 }
487 
488 template <class T>
489 typename ::std::enable_if<detail::is_canopen_basic<T>::value, T>::type
490 Device::RpdoRead(uint8_t id, uint16_t idx, uint8_t subidx) const {
491  ::std::error_code ec;
492  T value(RpdoRead<T>(id, idx, subidx, ec));
493  if (ec) throw_sdo_error(id, idx, subidx, ec, "RpdoRead");
494  return value;
495 }
496 
497 template <class T>
498 typename ::std::enable_if<detail::is_canopen_basic<T>::value, T>::type
499 Device::RpdoRead(uint8_t id, uint16_t idx, uint8_t subidx,
500  ::std::error_code& ec) const {
501  ec.clear();
502  {
503  ::std::lock_guard<Impl_> lock(*impl_);
504  ::std::tie(idx, subidx) = impl_->RpdoMapping(id, idx, subidx, ec);
505  }
506  if (ec) return T();
507  return Read<T>(idx, subidx, ec);
508 }
509 
510 template <class T>
511 typename ::std::enable_if<detail::is_canopen_basic<T>::value, T>::type
512 Device::TpdoRead(uint8_t id, uint16_t idx, uint8_t subidx) const {
513  ::std::error_code ec;
514  T value(TpdoRead<T>(id, idx, subidx, ec));
515  if (ec) throw_sdo_error(id, idx, subidx, ec, "TpdoRead");
516  return value;
517 }
518 
519 template <class T>
520 typename ::std::enable_if<detail::is_canopen_basic<T>::value, T>::type
521 Device::TpdoRead(uint8_t id, uint16_t idx, uint8_t subidx,
522  ::std::error_code& ec) const {
523  ec.clear();
524  {
525  ::std::lock_guard<Impl_> lock(*impl_);
526  ::std::tie(idx, subidx) = impl_->TpdoMapping(id, idx, subidx, ec);
527  }
528  if (ec) return T();
529  return Read<T>(idx, subidx, ec);
530 }
531 
532 template <class T>
533 typename ::std::enable_if<detail::is_canopen_basic<T>::value>::type
534 Device::TpdoWrite(uint8_t id, uint16_t idx, uint8_t subidx, T value) {
535  ::std::error_code ec;
536  TpdoWrite(id, idx, subidx, value, ec);
537  if (ec) throw_sdo_error(id, idx, subidx, ec, "TpdoWrite");
538 }
539 
540 template <class T>
541 typename ::std::enable_if<detail::is_canopen_basic<T>::value>::type
542 Device::TpdoWrite(uint8_t id, uint16_t idx, uint8_t subidx, T value,
543  ::std::error_code& ec) {
544  ec.clear();
545  {
546  ::std::lock_guard<Impl_> lock(*impl_);
547  ::std::tie(idx, subidx) = impl_->TpdoMapping(id, idx, subidx, ec);
548  }
549  if (!ec) Write<T>(idx, subidx, value, ec);
550 }
551 
552 #ifndef DOXYGEN_SHOULD_SKIP_THIS
553 
554 // BOOLEAN
555 template bool Device::RpdoRead<bool>(uint8_t, uint16_t, uint8_t) const;
556 template bool Device::RpdoRead<bool>(uint8_t, uint16_t, uint8_t,
557  ::std::error_code&) const;
558 template bool Device::TpdoRead<bool>(uint8_t, uint16_t, uint8_t) const;
559 template bool Device::TpdoRead<bool>(uint8_t, uint16_t, uint8_t,
560  ::std::error_code&) const;
561 template void Device::TpdoWrite<bool>(uint8_t, uint16_t, uint8_t, bool);
562 template void Device::TpdoWrite<bool>(uint8_t, uint16_t, uint8_t, bool,
563  ::std::error_code&);
564 
565 // INTEGER8
566 template int8_t Device::RpdoRead<int8_t>(uint8_t, uint16_t, uint8_t) const;
567 template int8_t Device::RpdoRead<int8_t>(uint8_t, uint16_t, uint8_t,
568  ::std::error_code&) const;
569 template int8_t Device::TpdoRead<int8_t>(uint8_t, uint16_t, uint8_t) const;
570 template int8_t Device::TpdoRead<int8_t>(uint8_t, uint16_t, uint8_t,
571  ::std::error_code&) const;
572 template void Device::TpdoWrite<int8_t>(uint8_t, uint16_t, uint8_t, int8_t);
573 template void Device::TpdoWrite<int8_t>(uint8_t, uint16_t, uint8_t, int8_t,
574  ::std::error_code&);
575 
576 // INTEGER16
577 template int16_t Device::RpdoRead<int16_t>(uint8_t, uint16_t, uint8_t) const;
578 template int16_t Device::RpdoRead<int16_t>(uint8_t, uint16_t, uint8_t,
579  ::std::error_code&) const;
580 template int16_t Device::TpdoRead<int16_t>(uint8_t, uint16_t, uint8_t) const;
581 template int16_t Device::TpdoRead<int16_t>(uint8_t, uint16_t, uint8_t,
582  ::std::error_code&) const;
583 template void Device::TpdoWrite<int16_t>(uint8_t, uint16_t, uint8_t, int16_t);
584 template void Device::TpdoWrite<int16_t>(uint8_t, uint16_t, uint8_t, int16_t,
585  ::std::error_code&);
586 
587 // INTEGER32
588 template int32_t Device::RpdoRead<int32_t>(uint8_t, uint16_t, uint8_t) const;
589 template int32_t Device::RpdoRead<int32_t>(uint8_t, uint16_t, uint8_t,
590  ::std::error_code&) const;
591 template int32_t Device::TpdoRead<int32_t>(uint8_t, uint16_t, uint8_t) const;
592 template int32_t Device::TpdoRead<int32_t>(uint8_t, uint16_t, uint8_t,
593  ::std::error_code&) const;
594 template void Device::TpdoWrite<int32_t>(uint8_t, uint16_t, uint8_t, int32_t);
595 template void Device::TpdoWrite<int32_t>(uint8_t, uint16_t, uint8_t, int32_t,
596  ::std::error_code&);
597 
598 // UNSIGNED8
599 template uint8_t Device::RpdoRead<uint8_t>(uint8_t, uint16_t, uint8_t) const;
600 template uint8_t Device::RpdoRead<uint8_t>(uint8_t, uint16_t, uint8_t,
601  ::std::error_code&) const;
602 template uint8_t Device::TpdoRead<uint8_t>(uint8_t, uint16_t, uint8_t) const;
603 template uint8_t Device::TpdoRead<uint8_t>(uint8_t, uint16_t, uint8_t,
604  ::std::error_code&) const;
605 template void Device::TpdoWrite<uint8_t>(uint8_t, uint16_t, uint8_t, uint8_t);
606 template void Device::TpdoWrite<uint8_t>(uint8_t, uint16_t, uint8_t, uint8_t,
607  ::std::error_code&);
608 
609 // UNSIGNED16
610 template uint16_t Device::RpdoRead<uint16_t>(uint8_t, uint16_t, uint8_t) const;
611 template uint16_t Device::RpdoRead<uint16_t>(uint8_t, uint16_t, uint8_t,
612  ::std::error_code&) const;
613 template uint16_t Device::TpdoRead<uint16_t>(uint8_t, uint16_t, uint8_t) const;
614 template uint16_t Device::TpdoRead<uint16_t>(uint8_t, uint16_t, uint8_t,
615  ::std::error_code&) const;
616 template void Device::TpdoWrite<uint16_t>(uint8_t, uint16_t, uint8_t, uint16_t);
617 template void Device::TpdoWrite<uint16_t>(uint8_t, uint16_t, uint8_t, uint16_t,
618  ::std::error_code&);
619 
620 // UNSIGNED32
621 template uint32_t Device::RpdoRead<uint32_t>(uint8_t, uint16_t, uint8_t) const;
622 template uint32_t Device::RpdoRead<uint32_t>(uint8_t, uint16_t, uint8_t,
623  ::std::error_code&) const;
624 template uint32_t Device::TpdoRead<uint32_t>(uint8_t, uint16_t, uint8_t) const;
625 template uint32_t Device::TpdoRead<uint32_t>(uint8_t, uint16_t, uint8_t,
626  ::std::error_code&) const;
627 template void Device::TpdoWrite<uint32_t>(uint8_t, uint16_t, uint8_t, uint32_t);
628 template void Device::TpdoWrite<uint32_t>(uint8_t, uint16_t, uint8_t, uint32_t,
629  ::std::error_code&);
630 
631 // REAL32
632 template float Device::RpdoRead<float>(uint8_t, uint16_t, uint8_t) const;
633 template float Device::RpdoRead<float>(uint8_t, uint16_t, uint8_t,
634  ::std::error_code&) const;
635 template float Device::TpdoRead<float>(uint8_t, uint16_t, uint8_t) const;
636 template float Device::TpdoRead<float>(uint8_t, uint16_t, uint8_t,
637  ::std::error_code&) const;
638 template void Device::TpdoWrite<float>(uint8_t, uint16_t, uint8_t, float);
639 template void Device::TpdoWrite<float>(uint8_t, uint16_t, uint8_t, float,
640  ::std::error_code&);
641 
642 // VISIBLE_STRING
643 // OCTET_STRING
644 // UNICODE_STRING
645 // TIME_OF_DAY
646 // TIME_DIFFERENCE
647 // DOMAIN
648 // INTEGER24
649 
650 // REAL64
651 template double Device::RpdoRead<double>(uint8_t, uint16_t, uint8_t) const;
652 template double Device::RpdoRead<double>(uint8_t, uint16_t, uint8_t,
653  ::std::error_code&) const;
654 template double Device::TpdoRead<double>(uint8_t, uint16_t, uint8_t) const;
655 template double Device::TpdoRead<double>(uint8_t, uint16_t, uint8_t,
656  ::std::error_code&) const;
657 template void Device::TpdoWrite<double>(uint8_t, uint16_t, uint8_t, double);
658 template void Device::TpdoWrite<double>(uint8_t, uint16_t, uint8_t, double,
659  ::std::error_code&);
660 
661 // INTEGER40
662 // INTEGER48
663 // INTEGER56
664 
665 // INTEGER64
666 template int64_t Device::RpdoRead<int64_t>(uint8_t, uint16_t, uint8_t) const;
667 template int64_t Device::RpdoRead<int64_t>(uint8_t, uint16_t, uint8_t,
668  ::std::error_code&) const;
669 template int64_t Device::TpdoRead<int64_t>(uint8_t, uint16_t, uint8_t) const;
670 template int64_t Device::TpdoRead<int64_t>(uint8_t, uint16_t, uint8_t,
671  ::std::error_code&) const;
672 template void Device::TpdoWrite<int64_t>(uint8_t, uint16_t, uint8_t, int64_t);
673 template void Device::TpdoWrite<int64_t>(uint8_t, uint16_t, uint8_t, int64_t,
674  ::std::error_code&);
675 
676 // UNSIGNED24
677 // UNSIGNED40
678 // UNSIGNED48
679 // UNSIGNED56
680 
681 // UNSIGNED64
682 template uint64_t Device::RpdoRead<uint64_t>(uint8_t, uint16_t, uint8_t) const;
683 template uint64_t Device::RpdoRead<uint64_t>(uint8_t, uint16_t, uint8_t,
684  ::std::error_code&) const;
685 template uint64_t Device::TpdoRead<uint64_t>(uint8_t, uint16_t, uint8_t) const;
686 template uint64_t Device::TpdoRead<uint64_t>(uint8_t, uint16_t, uint8_t,
687  ::std::error_code&) const;
688 template void Device::TpdoWrite<uint64_t>(uint8_t, uint16_t, uint8_t, uint64_t);
689 template void Device::TpdoWrite<uint64_t>(uint8_t, uint16_t, uint8_t, uint64_t,
690  ::std::error_code&);
691 
692 #endif // DOXYGEN_SHOULD_SKIP_THIS
693 
694 void
695 Device::TpdoWriteEvent(uint8_t id, uint16_t idx, uint8_t subidx) {
696  ::std::error_code ec;
697  TpdoWriteEvent(id, idx, subidx, ec);
698  if (ec) throw_sdo_error(id, idx, subidx, ec, "TpdoWriteEvent");
699 }
700 
701 void
702 Device::TpdoWriteEvent(uint8_t id, uint16_t idx, uint8_t subidx,
703  ::std::error_code& ec) noexcept {
704  ::std::lock_guard<Impl_> lock(*impl_);
705 
706  TpdoSetEvent(id, idx, subidx, ec);
707 }
708 
709 void
710 Device::OnWrite(::std::function<void(uint16_t, uint8_t)> on_write) {
711  ::std::lock_guard<Impl_> lock(*impl_);
712  impl_->on_write = on_write;
713 }
714 
715 void
716 Device::OnRpdoWrite(
717  ::std::function<void(uint8_t, uint16_t, uint8_t)> on_rpdo_write) {
718  ::std::lock_guard<Impl_> lock(*impl_);
719  impl_->on_rpdo_write = on_rpdo_write;
720 }
721 
722 CODev*
723 Device::dev() const noexcept {
724  return impl_->dev.get();
725 }
726 
727 const ::std::type_info&
728 Device::Type(uint16_t idx, uint8_t subidx) const {
729  ::std::error_code ec;
730  auto& ti = Type(idx, subidx, ec);
731  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "Type");
732  return ti;
733 }
734 
735 const ::std::type_info&
736 Device::Type(uint16_t idx, uint8_t subidx, ::std::error_code& ec) const
737  noexcept {
738  auto obj = impl_->dev->find(idx);
739  if (!obj) {
740  ec = SdoErrc::NO_OBJ;
741  return typeid(void);
742  }
743 
744  auto sub = obj->find(subidx);
745  if (!sub) {
746  ec = SdoErrc::NO_SUB;
747  return typeid(void);
748  }
749 
750  ec.clear();
751  switch (sub->getType()) {
752  case CO_DEFTYPE_BOOLEAN:
753  return typeid(bool);
754  case CO_DEFTYPE_INTEGER8:
755  return typeid(int8_t);
757  return typeid(int16_t);
759  return typeid(int32_t);
761  return typeid(uint8_t);
763  return typeid(uint16_t);
765  return typeid(uint32_t);
766  case CO_DEFTYPE_REAL32:
767  return typeid(float);
769  return typeid(::std::string);
771  return typeid(::std::vector<uint8_t>);
773  return typeid(::std::basic_string<char16_t>);
774  // case CO_DEFTYPE_TIME_OF_DAY: ...
775  // case CO_DEFTYPE_TIME_DIFFERENCE: ...
776  case CO_DEFTYPE_DOMAIN:
777  return typeid(::std::vector<uint8_t>);
778  // case CO_DEFTYPE_INTEGER24: ...
779  case CO_DEFTYPE_REAL64:
780  return typeid(double);
781  // case CO_DEFTYPE_INTEGER40: ...
782  // case CO_DEFTYPE_INTEGER48: ...
783  // case CO_DEFTYPE_INTEGER56: ...
785  return typeid(int64_t);
786  // case CO_DEFTYPE_UNSIGNED24: ...
787  // case CO_DEFTYPE_UNSIGNED40: ...
788  // case CO_DEFTYPE_UNSIGNED48: ...
789  // case CO_DEFTYPE_UNSIGNED56: ...
791  return typeid(uint64_t);
792  default:
793  return typeid(void);
794  }
795 }
796 
797 template <class T>
798 typename ::std::enable_if<detail::is_canopen_type<T>::value, T>::type
799 Device::Get(uint16_t idx, uint8_t subidx) const {
800  ::std::error_code ec;
801  auto value = Get<T>(idx, subidx, ec);
802  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "Get");
803  return value;
804 }
805 
806 template <class T>
807 typename ::std::enable_if<detail::is_canopen_type<T>::value, T>::type
808 Device::Get(uint16_t idx, uint8_t subidx, ::std::error_code& ec) const
809  noexcept {
810  constexpr auto N = co_type_traits_T<T>::index;
811 
812  auto obj = impl_->dev->find(idx);
813  if (!obj) {
814  ec = SdoErrc::NO_OBJ;
815  return T();
816  }
817 
818  auto sub = obj->find(subidx);
819  if (!sub) {
820  ec = SdoErrc::NO_SUB;
821  return T();
822  }
823 
824  if (!detail::is_canopen_same(N, sub->getType())) {
825  ec = SdoErrc::TYPE_LEN;
826  return T();
827  }
828 
829  ec.clear();
830  // This is efficient, even for CANopen array values, since getVal<N>() returns
831  // a reference.
832  return sub->getVal<N>();
833 }
834 
835 template <class T>
836 typename ::std::enable_if<detail::is_canopen_basic<T>::value>::type
837 Device::Set(uint16_t idx, uint8_t subidx, T value) {
838  ::std::error_code ec;
839  Set(idx, subidx, value, ec);
840  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "Set");
841 }
842 
843 template <class T>
844 typename ::std::enable_if<detail::is_canopen_basic<T>::value>::type
845 Device::Set(uint16_t idx, uint8_t subidx, T value,
846  ::std::error_code& ec) noexcept {
847  constexpr auto N = co_type_traits_T<T>::index;
848 
849  impl_->Set<N>(idx, subidx, &value, sizeof(value), ec);
850 }
851 
852 template <class T>
853 typename ::std::enable_if<detail::is_canopen_array<T>::value>::type
854 Device::Set(uint16_t idx, uint8_t subidx, const T& value) {
855  ::std::error_code ec;
856  Set(idx, subidx, value, ec);
857  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "Set");
858 }
859 
860 template <class T>
861 typename ::std::enable_if<detail::is_canopen_array<T>::value>::type
862 Device::Set(uint16_t idx, uint8_t subidx, const T& value,
863  ::std::error_code& ec) noexcept {
864  impl_->Set(idx, subidx, value, ec);
865 }
866 
867 #ifndef DOXYGEN_SHOULD_SKIP_THIS
868 
869 // BOOLEAN
870 template bool Device::Get<bool>(uint16_t, uint8_t) const;
871 template bool Device::Get<bool>(uint16_t, uint8_t, ::std::error_code&) const
872  noexcept;
873 template void Device::Set<bool>(uint16_t, uint8_t, bool);
874 template void Device::Set<bool>(uint16_t, uint8_t, bool,
875  ::std::error_code&) noexcept;
876 
877 // INTEGER8
878 template int8_t Device::Get<int8_t>(uint16_t, uint8_t) const;
879 template int8_t Device::Get<int8_t>(uint16_t, uint8_t, ::std::error_code&) const
880  noexcept;
881 template void Device::Set<int8_t>(uint16_t, uint8_t, int8_t);
882 template void Device::Set<int8_t>(uint16_t, uint8_t, int8_t,
883  ::std::error_code&) noexcept;
884 
885 // INTEGER16
886 template int16_t Device::Get<int16_t>(uint16_t, uint8_t) const;
887 template int16_t Device::Get<int16_t>(uint16_t, uint8_t,
888  ::std::error_code&) const noexcept;
889 template void Device::Set<int16_t>(uint16_t, uint8_t, int16_t);
890 template void Device::Set<int16_t>(uint16_t, uint8_t, int16_t,
891  ::std::error_code&) noexcept;
892 
893 // INTEGER32
894 template int32_t Device::Get<int32_t>(uint16_t, uint8_t) const;
895 template int32_t Device::Get<int32_t>(uint16_t, uint8_t,
896  ::std::error_code&) const noexcept;
897 template void Device::Set<int32_t>(uint16_t, uint8_t, int32_t);
898 template void Device::Set<int32_t>(uint16_t, uint8_t, int32_t,
899  ::std::error_code&) noexcept;
900 
901 // UNSIGNED8
902 template uint8_t Device::Get<uint8_t>(uint16_t, uint8_t) const;
903 template uint8_t Device::Get<uint8_t>(uint16_t, uint8_t,
904  ::std::error_code&) const noexcept;
905 template void Device::Set<uint8_t>(uint16_t, uint8_t, uint8_t);
906 template void Device::Set<uint8_t>(uint16_t, uint8_t, uint8_t,
907  ::std::error_code&) noexcept;
908 
909 // UNSIGNED16
910 template uint16_t Device::Get<uint16_t>(uint16_t, uint8_t) const;
911 template uint16_t Device::Get<uint16_t>(uint16_t, uint8_t,
912  ::std::error_code&) const noexcept;
913 template void Device::Set<uint16_t>(uint16_t, uint8_t, uint16_t);
914 template void Device::Set<uint16_t>(uint16_t, uint8_t, uint16_t,
915  ::std::error_code&) noexcept;
916 
917 // UNSIGNED32
918 template uint32_t Device::Get<uint32_t>(uint16_t, uint8_t) const;
919 template uint32_t Device::Get<uint32_t>(uint16_t, uint8_t,
920  ::std::error_code&) const noexcept;
921 template void Device::Set<uint32_t>(uint16_t, uint8_t, uint32_t);
922 template void Device::Set<uint32_t>(uint16_t, uint8_t, uint32_t,
923  ::std::error_code&) noexcept;
924 
925 // REAL32
926 template float Device::Get<float>(uint16_t, uint8_t) const;
927 template float Device::Get<float>(uint16_t, uint8_t, ::std::error_code&) const
928  noexcept;
929 template void Device::Set<float>(uint16_t, uint8_t, float);
930 template void Device::Set<float>(uint16_t, uint8_t, float,
931  ::std::error_code&) noexcept;
932 
933 // VISIBLE_STRING
934 template ::std::string Device::Get<::std::string>(uint16_t, uint8_t) const;
935 template ::std::string Device::Get<::std::string>(uint16_t, uint8_t,
936  ::std::error_code&) const
937  noexcept;
938 template void Device::Set<::std::string>(uint16_t, uint8_t,
939  const ::std::string&);
940 template void Device::Set<::std::string>(uint16_t, uint8_t,
941  const ::std::string&,
942  ::std::error_code&) noexcept;
943 
944 // OCTET_STRING
945 template ::std::vector<uint8_t> Device::Get<::std::vector<uint8_t>>(
946  uint16_t, uint8_t) const;
947 template ::std::vector<uint8_t> Device::Get<::std::vector<uint8_t>>(
948  uint16_t, uint8_t, ::std::error_code&) const noexcept;
949 template void Device::Set<::std::vector<uint8_t>>(
950  uint16_t, uint8_t, const ::std::vector<uint8_t>&);
951 template void Device::Set<::std::vector<uint8_t>>(uint16_t, uint8_t,
952  const ::std::vector<uint8_t>&,
953  ::std::error_code&) noexcept;
954 
955 // UNICODE_STRING
956 template ::std::basic_string<char16_t>
957  Device::Get<::std::basic_string<char16_t>>(uint16_t, uint8_t) const;
958 template ::std::basic_string<char16_t>
959 Device::Get<::std::basic_string<char16_t>>(uint16_t, uint8_t,
960  ::std::error_code&) const noexcept;
961 template void Device::Set<::std::basic_string<char16_t>>(
962  uint16_t, uint8_t, const ::std::basic_string<char16_t>&);
963 template void Device::Set<::std::basic_string<char16_t>>(
964  uint16_t, uint8_t, const ::std::basic_string<char16_t>&,
965  ::std::error_code&) noexcept;
966 
967 // TIME_OF_DAY
968 // TIME_DIFFERENCE
969 // DOMAIN
970 // INTEGER24
971 
972 // REAL64
973 template double Device::Get<double>(uint16_t, uint8_t) const;
974 template double Device::Get<double>(uint16_t, uint8_t, ::std::error_code&) const
975  noexcept;
976 template void Device::Set<double>(uint16_t, uint8_t, double);
977 template void Device::Set<double>(uint16_t, uint8_t, double,
978  ::std::error_code&) noexcept;
979 
980 // INTEGER40
981 // INTEGER48
982 // INTEGER56
983 
984 // INTEGER64
985 template int64_t Device::Get<int64_t>(uint16_t, uint8_t) const;
986 template int64_t Device::Get<int64_t>(uint16_t, uint8_t,
987  ::std::error_code&) const noexcept;
988 template void Device::Set<int64_t>(uint16_t, uint8_t, int64_t);
989 template void Device::Set<int64_t>(uint16_t, uint8_t, int64_t,
990  ::std::error_code&) noexcept;
991 
992 // UNSIGNED24
993 // UNSIGNED40
994 // UNSIGNED48
995 // UNSIGNED56
996 
997 // UNSIGNED64
998 template uint64_t Device::Get<uint64_t>(uint16_t, uint8_t) const;
999 template uint64_t Device::Get<uint64_t>(uint16_t, uint8_t,
1000  ::std::error_code&) const noexcept;
1001 template void Device::Set<uint64_t>(uint16_t, uint8_t, uint64_t);
1002 template void Device::Set<uint64_t>(uint16_t, uint8_t, uint64_t,
1003  ::std::error_code&) noexcept;
1004 
1005 #endif // DOXYGEN_SHOULD_SKIP_THIS
1006 
1007 void
1008 Device::Set(uint16_t idx, uint8_t subidx, const char* value) {
1009  ::std::error_code ec;
1010  Set(idx, subidx, value, ec);
1011  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "Set");
1012 }
1013 
1014 void
1015 Device::Set(uint16_t idx, uint8_t subidx, const char* value,
1016  ::std::error_code& ec) noexcept {
1017  impl_->Set<CO_DEFTYPE_VISIBLE_STRING>(idx, subidx, value, 0, ec);
1018 }
1019 
1020 void
1021 Device::Set(uint16_t idx, uint8_t subidx, const char16_t* value) {
1022  ::std::error_code ec;
1023  Set(idx, subidx, value, ec);
1024  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "Set");
1025 }
1026 
1027 void
1028 Device::Set(uint16_t idx, uint8_t subidx, const char16_t* value,
1029  ::std::error_code& ec) noexcept {
1030  impl_->Set<CO_DEFTYPE_UNICODE_STRING>(idx, subidx, value, 0, ec);
1031 }
1032 
1033 void
1034 Device::Set(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n) {
1035  ::std::error_code ec;
1036  Set(idx, subidx, p, n, ec);
1037  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "Set");
1038 }
1039 
1040 void
1041 Device::Set(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n,
1042  ::std::error_code& ec) noexcept {
1043  impl_->Set<CO_DEFTYPE_OCTET_STRING>(idx, subidx, p, n, ec);
1044 }
1045 
1046 const char*
1047 Device::GetUploadFile(uint16_t idx, uint8_t subidx) const {
1048  ::std::error_code ec;
1049  auto filename = GetUploadFile(idx, subidx, ec);
1050  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "GetUploadFile");
1051  return filename;
1052 }
1053 
1054 const char*
1055 Device::GetUploadFile(uint16_t idx, uint8_t subidx, ::std::error_code& ec) const
1056  noexcept {
1057  auto obj = impl_->dev->find(idx);
1058  if (!obj) {
1059  ec = SdoErrc::NO_OBJ;
1060  return nullptr;
1061  }
1062 
1063  auto sub = obj->find(subidx);
1064  if (!sub) {
1065  ec = SdoErrc::NO_SUB;
1066  return nullptr;
1067  }
1068 
1069  ec.clear();
1070  return sub->getUploadFile();
1071 }
1072 
1073 void
1074 Device::SetUploadFile(uint16_t idx, uint8_t subidx, const char* filename) {
1075  ::std::error_code ec;
1076  SetUploadFile(idx, subidx, filename, ec);
1077  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "SetUploadFile");
1078 }
1079 
1080 void
1081 Device::SetUploadFile(uint16_t idx, uint8_t subidx, const char* filename,
1082  ::std::error_code& ec) noexcept {
1083  auto obj = impl_->dev->find(idx);
1084  if (!obj) {
1085  ec = SdoErrc::NO_OBJ;
1086  return;
1087  }
1088 
1089  auto sub = obj->find(subidx);
1090  if (!sub) {
1091  ec = SdoErrc::NO_SUB;
1092  return;
1093  }
1094 
1095  int errsv = get_errc();
1096  set_errc(0);
1097  if (!sub->setUploadFile(filename))
1098  ec.clear();
1099  else
1100  ec = util::make_error_code();
1101  set_errc(errsv);
1102 }
1103 
1104 const char*
1105 Device::GetDownloadFile(uint16_t idx, uint8_t subidx) const {
1106  ::std::error_code ec;
1107  auto filename = GetDownloadFile(idx, subidx, ec);
1108  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "GetDownloadFile");
1109  return filename;
1110 }
1111 
1112 const char*
1113 Device::GetDownloadFile(uint16_t idx, uint8_t subidx,
1114  ::std::error_code& ec) const noexcept {
1115  auto obj = impl_->dev->find(idx);
1116  if (!obj) {
1117  ec = SdoErrc::NO_OBJ;
1118  return nullptr;
1119  }
1120 
1121  auto sub = obj->find(subidx);
1122  if (!sub) {
1123  ec = SdoErrc::NO_SUB;
1124  return nullptr;
1125  }
1126 
1127  ec.clear();
1128  return sub->getDownloadFile();
1129 }
1130 
1131 void
1132 Device::SetDownloadFile(uint16_t idx, uint8_t subidx, const char* filename) {
1133  ::std::error_code ec;
1134  SetDownloadFile(idx, subidx, filename, ec);
1135  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "SetDownloadFile");
1136 }
1137 
1138 void
1139 Device::SetDownloadFile(uint16_t idx, uint8_t subidx, const char* filename,
1140  ::std::error_code& ec) noexcept {
1141  auto obj = impl_->dev->find(idx);
1142  if (!obj) {
1143  ec = SdoErrc::NO_OBJ;
1144  return;
1145  }
1146 
1147  auto sub = obj->find(subidx);
1148  if (!sub) {
1149  ec = SdoErrc::NO_SUB;
1150  return;
1151  }
1152 
1153  int errsv = get_errc();
1154  set_errc(0);
1155  if (!sub->setDownloadFile(filename))
1156  ec.clear();
1157  else
1158  ec = util::make_error_code();
1159  set_errc(errsv);
1160 }
1161 
1162 void
1163 Device::SetEvent(uint16_t idx, uint8_t subidx) {
1164  ::std::error_code ec;
1165  SetEvent(idx, subidx, ec);
1166  if (ec) throw_sdo_error(impl_->id(), idx, subidx, ec, "SetEvent");
1167 }
1168 
1169 void
1170 Device::SetEvent(uint16_t idx, uint8_t subidx, ::std::error_code& ec) noexcept {
1171  auto obj = impl_->dev->find(idx);
1172  if (!obj) {
1173  ec = SdoErrc::NO_OBJ;
1174  return;
1175  }
1176 
1177  auto sub = obj->find(subidx);
1178  if (!sub) {
1179  ec = SdoErrc::NO_SUB;
1180  return;
1181  }
1182 
1183  impl_->dev->TPDOEvent(idx, subidx);
1184 }
1185 
1186 template <class T>
1187 typename ::std::enable_if<detail::is_canopen_basic<T>::value, T>::type
1188 Device::RpdoGet(uint8_t id, uint16_t idx, uint8_t subidx) const {
1189  ::std::error_code ec;
1190  auto value = RpdoGet<T>(id, idx, subidx, ec);
1191  if (ec) throw_sdo_error(id, idx, subidx, ec, "RpdoGet");
1192  return value;
1193 }
1194 
1195 template <class T>
1196 typename ::std::enable_if<detail::is_canopen_basic<T>::value, T>::type
1197 Device::RpdoGet(uint8_t id, uint16_t idx, uint8_t subidx,
1198  ::std::error_code& ec) const noexcept {
1199  ec.clear();
1200  ::std::tie(idx, subidx) = impl_->RpdoMapping(id, idx, subidx, ec);
1201  if (ec) return T();
1202  return Get<T>(idx, subidx, ec);
1203 }
1204 
1205 template <class T>
1206 typename ::std::enable_if<detail::is_canopen_basic<T>::value, T>::type
1207 Device::TpdoGet(uint8_t id, uint16_t idx, uint8_t subidx) const {
1208  ::std::error_code ec;
1209  auto value = TpdoGet<T>(id, idx, subidx, ec);
1210  if (ec) throw_sdo_error(id, idx, subidx, ec, "TpdoGet");
1211  return value;
1212 }
1213 
1214 template <class T>
1215 typename ::std::enable_if<detail::is_canopen_basic<T>::value, T>::type
1216 Device::TpdoGet(uint8_t id, uint16_t idx, uint8_t subidx,
1217  ::std::error_code& ec) const noexcept {
1218  ec.clear();
1219  ::std::tie(idx, subidx) = impl_->TpdoMapping(id, idx, subidx, ec);
1220  if (ec) return T();
1221  return Get<T>(idx, subidx, ec);
1222 }
1223 
1224 template <class T>
1225 typename ::std::enable_if<detail::is_canopen_basic<T>::value>::type
1226 Device::TpdoSet(uint8_t id, uint16_t idx, uint8_t subidx, T value) {
1227  ::std::error_code ec;
1228  TpdoSet(id, idx, subidx, value, ec);
1229  if (ec) throw_sdo_error(id, idx, subidx, ec, "TpdoSet");
1230 }
1231 
1232 template <class T>
1233 typename ::std::enable_if<detail::is_canopen_basic<T>::value>::type
1234 Device::TpdoSet(uint8_t id, uint16_t idx, uint8_t subidx, T value,
1235  ::std::error_code& ec) noexcept {
1236  ec.clear();
1237  ::std::tie(idx, subidx) = impl_->TpdoMapping(id, idx, subidx, ec);
1238  if (!ec) Set<T>(idx, subidx, value, ec);
1239 }
1240 
1241 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1242 
1243 // BOOLEAN
1244 template bool Device::RpdoGet<bool>(uint8_t, uint16_t, uint8_t) const;
1245 template bool Device::RpdoGet<bool>(uint8_t, uint16_t, uint8_t,
1246  ::std::error_code&) const noexcept;
1247 template bool Device::TpdoGet<bool>(uint8_t, uint16_t, uint8_t) const;
1248 template bool Device::TpdoGet<bool>(uint8_t, uint16_t, uint8_t,
1249  ::std::error_code&) const noexcept;
1250 template void Device::TpdoSet<bool>(uint8_t, uint16_t, uint8_t, bool);
1251 template void Device::TpdoSet<bool>(uint8_t, uint16_t, uint8_t, bool,
1252  ::std::error_code&) noexcept;
1253 
1254 // INTEGER8
1255 template int8_t Device::RpdoGet<int8_t>(uint8_t, uint16_t, uint8_t) const;
1256 template int8_t Device::RpdoGet<int8_t>(uint8_t, uint16_t, uint8_t,
1257  ::std::error_code&) const noexcept;
1258 template int8_t Device::TpdoGet<int8_t>(uint8_t, uint16_t, uint8_t) const;
1259 template int8_t Device::TpdoGet<int8_t>(uint8_t, uint16_t, uint8_t,
1260  ::std::error_code&) const noexcept;
1261 template void Device::TpdoSet<int8_t>(uint8_t, uint16_t, uint8_t, int8_t);
1262 template void Device::TpdoSet<int8_t>(uint8_t, uint16_t, uint8_t, int8_t,
1263  ::std::error_code&) noexcept;
1264 
1265 // INTEGER16
1266 template int16_t Device::RpdoGet<int16_t>(uint8_t, uint16_t, uint8_t) const;
1267 template int16_t Device::RpdoGet<int16_t>(uint8_t, uint16_t, uint8_t,
1268  ::std::error_code&) const noexcept;
1269 template int16_t Device::TpdoGet<int16_t>(uint8_t, uint16_t, uint8_t) const;
1270 template int16_t Device::TpdoGet<int16_t>(uint8_t, uint16_t, uint8_t,
1271  ::std::error_code&) const noexcept;
1272 template void Device::TpdoSet<int16_t>(uint8_t, uint16_t, uint8_t, int16_t);
1273 template void Device::TpdoSet<int16_t>(uint8_t, uint16_t, uint8_t, int16_t,
1274  ::std::error_code&) noexcept;
1275 
1276 // INTEGER32
1277 template int32_t Device::RpdoGet<int32_t>(uint8_t, uint16_t, uint8_t) const;
1278 template int32_t Device::RpdoGet<int32_t>(uint8_t, uint16_t, uint8_t,
1279  ::std::error_code&) const noexcept;
1280 template int32_t Device::TpdoGet<int32_t>(uint8_t, uint16_t, uint8_t) const;
1281 template int32_t Device::TpdoGet<int32_t>(uint8_t, uint16_t, uint8_t,
1282  ::std::error_code&) const noexcept;
1283 template void Device::TpdoSet<int32_t>(uint8_t, uint16_t, uint8_t, int32_t);
1284 template void Device::TpdoSet<int32_t>(uint8_t, uint16_t, uint8_t, int32_t,
1285  ::std::error_code&) noexcept;
1286 
1287 // UNSIGNED8
1288 template uint8_t Device::RpdoGet<uint8_t>(uint8_t, uint16_t, uint8_t) const;
1289 template uint8_t Device::RpdoGet<uint8_t>(uint8_t, uint16_t, uint8_t,
1290  ::std::error_code&) const noexcept;
1291 template uint8_t Device::TpdoGet<uint8_t>(uint8_t, uint16_t, uint8_t) const;
1292 template uint8_t Device::TpdoGet<uint8_t>(uint8_t, uint16_t, uint8_t,
1293  ::std::error_code&) const noexcept;
1294 template void Device::TpdoSet<uint8_t>(uint8_t, uint16_t, uint8_t, uint8_t);
1295 template void Device::TpdoSet<uint8_t>(uint8_t, uint16_t, uint8_t, uint8_t,
1296  ::std::error_code&) noexcept;
1297 
1298 // UNSIGNED16
1299 template uint16_t Device::RpdoGet<uint16_t>(uint8_t, uint16_t, uint8_t) const;
1300 template uint16_t Device::RpdoGet<uint16_t>(uint8_t, uint16_t, uint8_t,
1301  ::std::error_code&) const noexcept;
1302 template uint16_t Device::TpdoGet<uint16_t>(uint8_t, uint16_t, uint8_t) const;
1303 template uint16_t Device::TpdoGet<uint16_t>(uint8_t, uint16_t, uint8_t,
1304  ::std::error_code&) const noexcept;
1305 template void Device::TpdoSet<uint16_t>(uint8_t, uint16_t, uint8_t, uint16_t);
1306 template void Device::TpdoSet<uint16_t>(uint8_t, uint16_t, uint8_t, uint16_t,
1307  ::std::error_code&) noexcept;
1308 
1309 // UNSIGNED32
1310 template uint32_t Device::RpdoGet<uint32_t>(uint8_t, uint16_t, uint8_t) const;
1311 template uint32_t Device::RpdoGet<uint32_t>(uint8_t, uint16_t, uint8_t,
1312  ::std::error_code&) const noexcept;
1313 template uint32_t Device::TpdoGet<uint32_t>(uint8_t, uint16_t, uint8_t) const;
1314 template uint32_t Device::TpdoGet<uint32_t>(uint8_t, uint16_t, uint8_t,
1315  ::std::error_code&) const noexcept;
1316 template void Device::TpdoSet<uint32_t>(uint8_t, uint16_t, uint8_t, uint32_t);
1317 template void Device::TpdoSet<uint32_t>(uint8_t, uint16_t, uint8_t, uint32_t,
1318  ::std::error_code&) noexcept;
1319 
1320 // REAL32
1321 template float Device::RpdoGet<float>(uint8_t, uint16_t, uint8_t) const;
1322 template float Device::RpdoGet<float>(uint8_t, uint16_t, uint8_t,
1323  ::std::error_code&) const noexcept;
1324 template float Device::TpdoGet<float>(uint8_t, uint16_t, uint8_t) const;
1325 template float Device::TpdoGet<float>(uint8_t, uint16_t, uint8_t,
1326  ::std::error_code&) const noexcept;
1327 template void Device::TpdoSet<float>(uint8_t, uint16_t, uint8_t, float);
1328 template void Device::TpdoSet<float>(uint8_t, uint16_t, uint8_t, float,
1329  ::std::error_code&) noexcept;
1330 
1331 // VISIBLE_STRING
1332 // OCTET_STRING
1333 // UNICODE_STRING
1334 // TIME_OF_DAY
1335 // TIME_DIFFERENCE
1336 // DOMAIN
1337 // INTEGER24
1338 
1339 // REAL64
1340 template double Device::RpdoGet<double>(uint8_t, uint16_t, uint8_t) const;
1341 template double Device::RpdoGet<double>(uint8_t, uint16_t, uint8_t,
1342  ::std::error_code&) const noexcept;
1343 template double Device::TpdoGet<double>(uint8_t, uint16_t, uint8_t) const;
1344 template double Device::TpdoGet<double>(uint8_t, uint16_t, uint8_t,
1345  ::std::error_code&) const noexcept;
1346 template void Device::TpdoSet<double>(uint8_t, uint16_t, uint8_t, double);
1347 template void Device::TpdoSet<double>(uint8_t, uint16_t, uint8_t, double,
1348  ::std::error_code&) noexcept;
1349 
1350 // INTEGER40
1351 // INTEGER48
1352 // INTEGER56
1353 
1354 // INTEGER64
1355 template int64_t Device::RpdoGet<int64_t>(uint8_t, uint16_t, uint8_t) const;
1356 template int64_t Device::RpdoGet<int64_t>(uint8_t, uint16_t, uint8_t,
1357  ::std::error_code&) const noexcept;
1358 template int64_t Device::TpdoGet<int64_t>(uint8_t, uint16_t, uint8_t) const;
1359 template int64_t Device::TpdoGet<int64_t>(uint8_t, uint16_t, uint8_t,
1360  ::std::error_code&) const noexcept;
1361 template void Device::TpdoSet<int64_t>(uint8_t, uint16_t, uint8_t, int64_t);
1362 template void Device::TpdoSet<int64_t>(uint8_t, uint16_t, uint8_t, int64_t,
1363  ::std::error_code&) noexcept;
1364 
1365 // UNSIGNED24
1366 // UNSIGNED40
1367 // UNSIGNED48
1368 // UNSIGNED56
1369 
1370 // UNSIGNED64
1371 template uint64_t Device::RpdoGet<uint64_t>(uint8_t, uint16_t, uint8_t) const;
1372 template uint64_t Device::RpdoGet<uint64_t>(uint8_t, uint16_t, uint8_t,
1373  ::std::error_code&) const noexcept;
1374 template uint64_t Device::TpdoGet<uint64_t>(uint8_t, uint16_t, uint8_t) const;
1375 template uint64_t Device::TpdoGet<uint64_t>(uint8_t, uint16_t, uint8_t,
1376  ::std::error_code&) const noexcept;
1377 template void Device::TpdoSet<uint64_t>(uint8_t, uint16_t, uint8_t, uint64_t);
1378 template void Device::TpdoSet<uint64_t>(uint8_t, uint16_t, uint8_t, uint64_t,
1379  ::std::error_code&) noexcept;
1380 
1381 #endif // DOXYGEN_SHOULD_SKIP_THIS
1382 
1383 void
1384 Device::TpdoSetEvent(uint8_t id, uint16_t idx, uint8_t subidx) {
1385  ::std::error_code ec;
1386  TpdoSetEvent(id, idx, subidx, ec);
1387  if (ec) throw_sdo_error(id, idx, subidx, ec, "TpdoSetEvent");
1388 }
1389 
1390 void
1391 Device::TpdoSetEvent(uint8_t id, uint16_t idx, uint8_t subidx,
1392  ::std::error_code& ec) noexcept {
1393  ec.clear();
1394  ::std::tie(idx, subidx) = impl_->TpdoMapping(id, idx, subidx, ec);
1395  if (!ec) SetEvent(idx, subidx, ec);
1396 }
1397 
1398 void
1400  impl_->rpdo_mapping.clear();
1401 
1402  for (int i = 0; i < 512; i++) {
1403  auto obj_1400 = impl_->dev->find(0x1400 + i);
1404  if (!obj_1400) continue;
1405  // Skip invalid PDOs.
1406  auto cobid = obj_1400->getVal<CO_DEFTYPE_UNSIGNED32>(1);
1407  if (cobid & CO_PDO_COBID_VALID) continue;
1408  // Obtain the remote node-ID.
1409  uint8_t id = 0;
1410  auto obj_5800 = impl_->dev->find(0x5800 + i);
1411  if (obj_5800) {
1412  id = obj_5800->getVal<CO_DEFTYPE_UNSIGNED32>(0) & 0xff;
1413  } else {
1414  // Obtain the node-ID from the predefined connection, if possible.
1415  if (cobid & CO_PDO_COBID_FRAME) continue;
1416  switch (cobid & 0x780) {
1417  case 0x180:
1418  case 0x280:
1419  case 0x380:
1420  case 0x480:
1421  id = cobid & 0x7f;
1422  break;
1423  default:
1424  continue;
1425  }
1426  }
1427  // Skip invalid node-IDs.
1428  if (!id || id > CO_NUM_NODES) continue;
1429  // Obtain the local RPDO mapping.
1430  auto obj_1600 = impl_->dev->find(0x1600 + i);
1431  if (!obj_1600) continue;
1432  // Obtain the remote TPDO mapping.
1433  auto obj_5a00 = impl_->dev->find(0x5a00 + i);
1434  if (!obj_5a00) continue;
1435  // Check if the number of mapped objects is the same.
1436  auto n = obj_1600->getVal<CO_DEFTYPE_UNSIGNED8>(0);
1437  if (n != obj_5a00->getVal<CO_DEFTYPE_UNSIGNED8>(0)) continue;
1438  for (int i = 1; i <= n; i++) {
1439  auto rmap = obj_1600->getVal<CO_DEFTYPE_UNSIGNED32>(i);
1440  auto tmap = obj_5a00->getVal<CO_DEFTYPE_UNSIGNED32>(i);
1441  // Ignore empty mapping entries.
1442  if (!rmap && !tmap) continue;
1443  // Check if the mapped objects have the same length.
1444  if ((rmap & 0xff) != (tmap & 0xff)) break;
1445  rmap >>= 8;
1446  tmap >>= 8;
1447  // Skip dummy-mapped objects.
1448  if (co_type_is_basic((rmap >> 8) & 0xffff) && !(rmap & 0xff)) continue;
1449  tmap |= static_cast<uint32_t>(id) << 24;
1450  impl_->rpdo_mapping[tmap] = rmap;
1451  // Store the reverse mapping for OnRpdoWrite().
1452  impl_->rpdo_mapping[rmap] = tmap;
1453  }
1454  }
1455 }
1456 
1457 void
1459  impl_->tpdo_mapping.clear();
1460 
1461  for (int i = 0; i < 512; i++) {
1462  auto obj_1800 = impl_->dev->find(0x1800 + i);
1463  if (!obj_1800) continue;
1464  // Skip invalid PDOs.
1465  auto cobid = obj_1800->getVal<CO_DEFTYPE_UNSIGNED32>(1);
1466  if (cobid & CO_PDO_COBID_VALID) continue;
1467  // Obtain the remote node-ID.
1468  uint8_t id = 0;
1469  auto obj_5c00 = impl_->dev->find(0x5c00 + i);
1470  if (obj_5c00) {
1471  id = obj_5c00->getVal<CO_DEFTYPE_UNSIGNED32>(0) & 0xff;
1472  } else {
1473  // Obtain the node-ID from the predefined connection, if possible.
1474  if (cobid & CO_PDO_COBID_FRAME) continue;
1475  switch (cobid & 0x780) {
1476  case 0x200:
1477  case 0x300:
1478  case 0x400:
1479  case 0x500:
1480  id = cobid & 0x7f;
1481  break;
1482  default:
1483  continue;
1484  }
1485  }
1486  // Skip invalid node-IDs.
1487  if (!id || id > CO_NUM_NODES) continue;
1488  // Obtain the local TPDO mapping.
1489  auto obj_1a00 = impl_->dev->find(0x1a00 + i);
1490  if (!obj_1a00) continue;
1491  // Obtain the remote RPDO mapping.
1492  auto obj_5e00 = impl_->dev->find(0x5e00 + i);
1493  if (!obj_5e00) continue;
1494  // Check if the number of mapped objects is the same.
1495  auto n = obj_1a00->getVal<CO_DEFTYPE_UNSIGNED8>(0);
1496  if (n != obj_5e00->getVal<CO_DEFTYPE_UNSIGNED8>(0)) continue;
1497  for (int i = 1; i <= n; i++) {
1498  auto tmap = obj_1a00->getVal<CO_DEFTYPE_UNSIGNED32>(i);
1499  auto rmap = obj_5e00->getVal<CO_DEFTYPE_UNSIGNED32>(i);
1500  // Ignore empty mapping entries.
1501  if (!rmap && !tmap) continue;
1502  // Check if the mapped objects have the same length.
1503  if ((tmap & 0xff) != (rmap & 0xff)) break;
1504  tmap >>= 8;
1505  rmap >>= 8;
1506  rmap |= static_cast<uint32_t>(id) << 24;
1507  impl_->tpdo_mapping[rmap] = tmap;
1508  }
1509  }
1510 }
1511 
1512 Device::Impl_::Impl_(Device* self_, const ::std::string& dcf_txt,
1513  const ::std::string& dcf_bin, uint8_t id,
1514  util::BasicLockable* mutex_)
1515  : self(self_), mutex(mutex_), dev(make_unique_c<CODev>(dcf_txt.c_str())) {
1516  if (!dcf_bin.empty() && dev->readDCF(nullptr, nullptr, dcf_bin.c_str()) == -1)
1517  util::throw_errc("Device");
1518 
1519  if (id != 0xff && dev->setId(id) == -1) util::throw_errc("Device");
1520 
1521  // Register a notification function for all objects in the object dictionary
1522  // in case of write (SDO upload) access.
1523  for (auto obj = co_dev_first_obj(dev.get()); obj; obj = co_obj_next(obj)) {
1524  // Skip data types and the communication profile area.
1525  if (obj->getIdx() < 0x2000) continue;
1526  // Skip reserved objects.
1527  if (obj->getIdx() >= 0xC000) break;
1528  obj->setDnInd(
1529  [](COSub* sub, co_sdo_req* req, void* data) -> uint32_t {
1530  // Implement the default behavior, but do not issue a notification for
1531  // incomplete or failed writes.
1532  uint32_t ac = 0;
1533  if (sub->onDn(*req, &ac) == -1 || ac) return ac;
1534  auto impl_ = static_cast<Impl_*>(data);
1535  impl_->OnWrite(sub->getObj()->getIdx(), sub->getSubidx());
1536  return 0;
1537  },
1538  static_cast<void*>(this));
1539  }
1540 }
1541 
1542 void
1543 Device::Impl_::Set(uint16_t idx, uint8_t subidx, const ::std::string& value,
1544  ::std::error_code& ec) noexcept {
1545  Set<CO_DEFTYPE_VISIBLE_STRING>(idx, subidx, value.c_str(), 0, ec);
1546 }
1547 
1548 void
1549 Device::Impl_::Set(uint16_t idx, uint8_t subidx,
1550  const ::std::vector<uint8_t>& value,
1551  ::std::error_code& ec) noexcept {
1552  Set<CO_DEFTYPE_OCTET_STRING>(idx, subidx, value.data(), value.size(), ec);
1553 }
1554 
1555 void
1556 Device::Impl_::Set(uint16_t idx, uint8_t subidx,
1557  const ::std::basic_string<char16_t>& value,
1558  ::std::error_code& ec) noexcept {
1559  Set<CO_DEFTYPE_UNICODE_STRING>(idx, subidx, value.c_str(), 0, ec);
1560 }
1561 
1562 template <uint16_t N>
1563 void
1564 Device::Impl_::Set(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n,
1565  ::std::error_code& ec) noexcept {
1566  auto obj = dev->find(idx);
1567  if (!obj) {
1568  ec = SdoErrc::NO_OBJ;
1569  return;
1570  }
1571 
1572  auto sub = obj->find(subidx);
1573  if (!sub) {
1574  ec = SdoErrc::NO_SUB;
1575  return;
1576  }
1577 
1578  if (!detail::is_canopen_same(N, sub->getType())) {
1579  ec = SdoErrc::TYPE_LEN;
1580  return;
1581  }
1582 
1583  int errsv = get_errc();
1584  set_errc(0);
1585  if (sub->setVal(p, n) == n)
1586  ec.clear();
1587  else
1588  ec = util::make_error_code();
1589  set_errc(errsv);
1590 }
1591 
1592 void
1593 Device::Impl_::OnWrite(uint16_t idx, uint8_t subidx) {
1594  self->OnWrite(idx, subidx);
1595 
1596  if (on_write) {
1597  auto f = on_write;
1598  util::UnlockGuard<Impl_> unlock(*this);
1599  f(idx, subidx);
1600  }
1601 
1602  uint8_t id = 0;
1603  ::std::error_code ec;
1604  ::std::tie(id, idx, subidx) = RpdoMapping(idx, subidx, ec);
1605  if (!ec) {
1606  self->OnRpdoWrite(id, idx, subidx);
1607 
1608  if (on_rpdo_write) {
1609  auto f = on_rpdo_write;
1610  util::UnlockGuard<Impl_> unlock(*this);
1611  f(id, idx, subidx);
1612  }
1613  }
1614 }
1615 
1616 } // namespace canopen
1617 
1618 } // namespace lely
CO_PDO_COBID_VALID
#define CO_PDO_COBID_VALID
The bit in the PDO COB-ID specifying whether the PDO exists and is valid.
Definition: pdo.h:28
CO_DEFTYPE_UNSIGNED64
#define CO_DEFTYPE_UNSIGNED64
The data type (and object index) of a 64-bit unsigned integer.
Definition: type.h:110
lely::util::BasicLockable
An abstract interface conforming to the BasicLockable concept.
Definition: mutex.hpp:34
lely::COCSDO
An opaque CANopen Client-SDO service type.
Definition: csdo.hpp:156
csdo.hpp
CO_DEFTYPE_INTEGER8
#define CO_DEFTYPE_INTEGER8
The data type (and object index) of an 8-bit signed integer.
Definition: type.h:35
CO_DEFTYPE_INTEGER64
#define CO_DEFTYPE_INTEGER64
The data type (and object index) of a 64-bit signed integer.
Definition: type.h:95
lely::canopen::Device::Set
typename ::std::enable_if< detail::is_canopen_basic< T >::value >::type Set(uint16_t idx, uint8_t subidx, T value)
Writes a CANopen basic value to a sub-object.
CO_PDO_COBID_FRAME
#define CO_PDO_COBID_FRAME
The bit in the PDO COB-ID specifying whether to use an 11-bit (0) or 29-bit (1) CAN-ID.
Definition: pdo.h:37
CO_DEFTYPE_UNSIGNED32
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
lely::canopen::SdoErrc::TYPE_LEN
@ TYPE_LEN
Data type does not match, length of service parameter does not match.
lely::canopen::Device::UpdateTpdoMapping
void UpdateTpdoMapping()
Updates the mapping from remote RPDO-mapped sub-objects to local TPDO-mapped sub-objects.
Definition: device.cpp:1458
device.hpp
CO_DEFTYPE_INTEGER32
#define CO_DEFTYPE_INTEGER32
The data type (and object index) of a 32-bit signed integer.
Definition: type.h:41
lely::canopen::Device::Impl_::lock
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: device.cpp:50
lely::canopen::Device::TpdoSetEvent
void TpdoSetEvent(uint8_t id, uint16_t idx, uint8_t subidx)
Triggers the transmission of every event-driven, asynchronous Transmit-PDO which is mapped into the s...
Definition: device.cpp:1384
CO_DEFTYPE_UNSIGNED16
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
lely::canopen::Device::GetUploadFile
const char * GetUploadFile(uint16_t idx, uint8_t subidx) const
Returns the value of the UploadFile attribute of a sub-object, if present.
Definition: device.cpp:1047
lely::canopen::SdoErrc::NO_PDO
@ NO_PDO
Object cannot be mapped to the PDO.
CO_NUM_NODES
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
lely::canopen::Device::Read
typename ::std::enable_if< detail::is_canopen_type< T >::value, T >::type Read(uint16_t idx, uint8_t subidx) const
Submits an SDO upload request to the local object dictionary.
co_type_is_basic
int co_type_is_basic(co_unsigned16_t type)
Returns 1 if the specified (static) data type is a basic type, and 0 if not.
Definition: type.c:28
lely::canopen::Device::RpdoRead
typename ::std::enable_if< detail::is_canopen_basic< T >::value, T >::type RpdoRead(uint8_t id, uint16_t idx, uint8_t subidx) const
Reads the value of a sub-object in a remote object dictionary by submitting an SDO upload request to ...
lely::canopen::throw_sdo_error
void throw_sdo_error(uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec)
Throws a lely::canopen::SdoError with the specified attributes if ec is an SDO error (ec....
Definition: sdo_error.hpp:219
lely::canopen::Device::Device
Device(const ::std::string &dcf_txt, const ::std::string &dcf_bin="", uint8_t id=0xff, util::BasicLockable *mutex=nullptr)
Creates a new CANopen device description.
Definition: device.cpp:147
get_errc
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
CO_DEFTYPE_BOOLEAN
#define CO_DEFTYPE_BOOLEAN
The data type (and object index) of a boolean truth value.
Definition: type.h:32
CO_DEFTYPE_VISIBLE_STRING
#define CO_DEFTYPE_VISIBLE_STRING
The data type (and object index) of an array of visible characters.
Definition: type.h:56
lely::canopen::Device::Impl_
The internal implementation of the CANopen device description.
Definition: device.cpp:44
CO_DEFTYPE_UNSIGNED8
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
CO_DEFTYPE_DOMAIN
#define CO_DEFTYPE_DOMAIN
The data type (and object index) of an arbitrary large block of data.
Definition: type.h:77
lely::canopen::SdoErrc::NO_OBJ
@ NO_OBJ
Object does not exist in the object dictionary.
lely::canopen::Device::netid
uint8_t netid() const noexcept
Returns the network-ID.
Definition: device.cpp:154
lely::canopen::Device::SetDownloadFile
void SetDownloadFile(uint16_t idx, uint8_t subidx, const char *filename)
Sets the value of the DownloadFile attribute of a sub-object, if present.
Definition: device.cpp:1132
co_dev_first_obj
co_obj_t * co_dev_first_obj(const co_dev_t *dev)
Finds the first object (with the lowest index) in the object dictionary of a CANopen device.
Definition: dev.c:306
CO_DEFTYPE_OCTET_STRING
#define CO_DEFTYPE_OCTET_STRING
The data type (and object index) of an array of octets.
Definition: type.h:59
CO_DEFTYPE_REAL64
#define CO_DEFTYPE_REAL64
The data type (and object index) of a 64-bit IEEE-754 floating-point number.
Definition: type.h:83
lely::canopen::Device::TpdoSet
typename ::std::enable_if< detail::is_canopen_basic< T >::value >::type TpdoSet(uint8_t id, uint16_t idx, uint8_t subidx, T value)
Writes a value to a sub-object in a remote object dictionary by writing to the corresponding PDO-mapp...
lely::canopen::Device::TpdoGet
typename ::std::enable_if< detail::is_canopen_basic< T >::value, T >::type TpdoGet(uint8_t id, uint16_t idx, uint8_t subidx) const
Reads the value of a TPDO-mapped sub-object in the local object dictionary that will be written to an...
obj.hpp
lely::canopen::Device::id
uint8_t id() const noexcept
Returns the node-ID.
Definition: device.cpp:161
lely::canopen::Device::SetUploadFile
void SetUploadFile(uint16_t idx, uint8_t subidx, const char *filename)
Sets the value of the UploadFile attribute of a sub-object, if present.
Definition: device.cpp:1074
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
lely::canopen::Device::Write
typename ::std::enable_if< detail::is_canopen_basic< T >::value >::type Write(uint16_t idx, uint8_t subidx, T value)
Submits an SDO download request to the local object dictionary.
co_sdo_req
A CANopen SDO upload/download request.
Definition: sdo.h:178
lely::canopen::Device::SetEvent
void SetEvent(uint16_t idx, uint8_t subidx)
Checks if the specified sub-object in the local object dictionary can be mapped into a PDO and,...
Definition: device.cpp:1163
lely::canopen::Device::dev
CODev * dev() const noexcept
Returns a pointer to the internal CANopen device from <lely/co/dev.hpp>.
Definition: device.cpp:723
lely::co_type_traits_T
A class template mapping CANopen types to C++ types.
Definition: type.hpp:59
lely::canopen::Device
The CANopen device description.
Definition: device.hpp:45
lely::canopen::Device::Get
typename ::std::enable_if< detail::is_canopen_type< T >::value, T >::type Get(uint16_t idx, uint8_t subidx) const
Reads the value of a sub-object.
lely::canopen::SdoErrc
SdoErrc
The SDO abort codes.
Definition: sdo_error.hpp:42
coapp.hpp
lely::canopen::Device::TpdoWriteEvent
void TpdoWriteEvent(uint8_t id, uint16_t idx, uint8_t subidx)
Triggers the transmission of every event-driven, asynchronous Transmit-PDO which is mapped into the s...
Definition: device.cpp:695
lely::util::BasicLockable::lock
virtual void lock()=0
Blocks until a lock can be obtained for the current execution agent (thread, process,...
dcf.hpp
lely::canopen::Device::Impl_::unlock
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
Definition: device.cpp:55
lely::canopen::detail::is_canopen_same
bool is_canopen_same(uint16_t t1, uint16_t t2)
Returns true if the CANopen data types t1 and t2 map to the same C++ type, and false if not.
Definition: type_traits.hpp:177
CO_DEFTYPE_REAL32
#define CO_DEFTYPE_REAL32
The data type (and object index) of a 32-bit IEEE-754 floating-point number.
Definition: type.h:53
lely::canopen::Device::GetDownloadFile
const char * GetDownloadFile(uint16_t idx, uint8_t subidx) const
Returns the value of the DownloadFile attribute of a sub-object, if present.
Definition: device.cpp:1105
lely::canopen::Device::TpdoWrite
typename ::std::enable_if< detail::is_canopen_basic< T >::value >::type TpdoWrite(uint8_t id, uint16_t idx, uint8_t subidx, T value)
Writes a value to a sub-object in a remote object dictionary by submitting an SDO download request to...
CO_DEFTYPE_INTEGER16
#define CO_DEFTYPE_INTEGER16
The data type (and object index) of a 16-bit signed integer.
Definition: type.h:38
CO_DEFTYPE_UNICODE_STRING
#define CO_DEFTYPE_UNICODE_STRING
The data type (and object index) of an array of (16-bit) Unicode characters.
Definition: type.h:62
pdo.h
lely::canopen::Device::Type
const ::std::type_info & Type(uint16_t idx, uint8_t subidx) const
Returns the type of a sub-object.
Definition: device.cpp:728
lely::canopen::make_error_code
::std::error_code make_error_code(SdoErrc e) noexcept
Creates an error code corresponding to an SDO abort code.
Definition: sdo_error.cpp:170
lely::canopen::Device::RpdoGet
typename ::std::enable_if< detail::is_canopen_basic< T >::value, T >::type RpdoGet(uint8_t id, uint16_t idx, uint8_t subidx) const
Reads the value of a sub-object in a remote object dictionary by reading the corresponding PDO-mapped...
lely::util::BasicLockable::unlock
virtual void unlock()=0
Releases the lock held by the execution agent. Throws no exceptions.
lely::canopen::Device::WriteEvent
void WriteEvent(uint16_t idx, uint8_t subidx)
Checks if the specified sub-object in the local object dictionary can be mapped into a PDO and,...
Definition: device.cpp:474
lely::make_unique_c
unique_c_ptr< T > make_unique_c(Args &&... args)
Creates an instance of a trivial, standard layout or incomplete C type and wraps it in a lely::unique...
Definition: c_type.hpp:111
lely::canopen::Device::TpdoRead
typename ::std::enable_if< detail::is_canopen_basic< T >::value, T >::type TpdoRead(uint8_t id, uint16_t idx, uint8_t subidx) const
Submits an SDO upload request to a TPDO-mapped sub-object in the local object dictionary,...
lely::canopen::Device::UpdateRpdoMapping
void UpdateRpdoMapping()
Updates the mapping from remote TPDO-mapped sub-objects to local RPDO-mapped sub-objects.
Definition: device.cpp:1399
lely::canopen::SdoErrc::NO_SUB
@ NO_SUB
Sub-index does not exist.
lely::CODev
An opaque CANopen device type.
Definition: dev.hpp:77
error.hpp
co_obj_next
co_obj_t * co_obj_next(const co_obj_t *obj)
Finds the next object in the object dictionary of a CANopen device.
Definition: obj.c:137
lely::COSub
An opaque CANopen sub-object type.
Definition: obj.hpp:229