Lely core libraries  1.9.2
device.cpp
Go to the documentation of this file.
1 
24 #include "coapp.hpp"
25 #include <lely/coapp/device.hpp>
26 
27 #include <mutex>
28 
29 #include <lely/co/csdo.hpp>
30 #include <lely/co/dcf.hpp>
31 #include <lely/co/obj.hpp>
32 
33 namespace lely {
34 
35 namespace canopen {
36 
38 struct Device::Impl_ : public BasicLockable {
39  Impl_(const ::std::string& dcf_txt, const ::std::string& dcf_bin, uint8_t id,
40  BasicLockable* mutex);
41 
42  virtual void
43  lock() override {
44  if (mutex) mutex->lock();
45  }
46  virtual void
47  unlock() override {
48  if (mutex) mutex->unlock();
49  }
50 
51  uint8_t
52  netid() const noexcept {
53  return dev->getNetid();
54  }
55  uint8_t
56  id() const noexcept {
57  return dev->getId();
58  }
59 
60  void Set(uint16_t idx, uint8_t subidx, const ::std::string& value,
61  ::std::error_code& ec);
62 
63  void Set(uint16_t idx, uint8_t subidx, const ::std::vector<uint8_t>& value,
64  ::std::error_code& ec);
65 
66  void Set(uint16_t idx, uint8_t subidx,
67  const ::std::basic_string<char16_t>& value, ::std::error_code& ec);
68 
69  template <uint16_t N>
70  void Set(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n,
71  ::std::error_code& ec);
72 
73  BasicLockable* mutex{nullptr};
74 
75  unique_c_ptr<CODev> dev;
76 };
77 
78 Device::Device(const ::std::string& dcf_txt, const ::std::string& dcf_bin,
79  uint8_t id, BasicLockable* mutex)
80  : impl_(new Impl_(dcf_txt, dcf_bin, id, mutex)) {}
81 
82 Device& Device::operator=(Device&&) = default;
83 
84 Device::~Device() = default;
85 
86 uint8_t
87 Device::netid() const noexcept {
88  ::std::lock_guard<Impl_> lock(*impl_);
89 
90  return impl_->netid();
91 }
92 
93 uint8_t
94 Device::id() const noexcept {
95  ::std::lock_guard<Impl_> lock(*impl_);
96 
97  return impl_->id();
98 }
99 
100 namespace {
101 
102 void
103 OnDnCon(COCSDO*, uint16_t, uint8_t, uint32_t ac, void* data) noexcept {
104  *static_cast<uint32_t*>(data) = ac;
105 }
106 
107 template <class T>
108 void
109 OnUpCon(COCSDO*, uint16_t, uint8_t, uint32_t ac, T value, void* data) noexcept {
110  auto* t = static_cast<decltype(::std::tie(ac, value))*>(data);
111  *t = ::std::forward_as_tuple(ac, ::std::move(value));
112 }
113 
114 } // namespace
115 
116 template <class T>
117 typename ::std::enable_if<detail::IsCanopenType<T>::value, T>::type
118 Device::Read(uint16_t idx, uint8_t subidx) const {
119  ::std::error_code ec;
120  T value(Read<T>(idx, subidx, ec));
121  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "Read");
122  return value;
123 }
124 
125 template <class T>
126 typename ::std::enable_if<detail::IsCanopenType<T>::value, T>::type
127 Device::Read(uint16_t idx, uint8_t subidx, ::std::error_code& ec) const {
128  uint32_t ac = 0;
129  T value = T();
130  auto t = ::std::tie(ac, value);
131 
132  ::std::lock_guard<Impl_> lock(*impl_);
133  if (upReq<T, &OnUpCon<T>>(*impl_->dev, idx, subidx, &t) == -1)
134  throw_errc("Read");
135 
136  if (ac)
137  ec = static_cast<SdoErrc>(ac);
138  else
139  ec.clear();
140  return value;
141 }
142 
143 template <class T>
144 typename ::std::enable_if<detail::IsCanopenBasic<T>::value>::type
145 Device::Write(uint16_t idx, uint8_t subidx, T value) {
146  ::std::error_code ec;
147  Write(idx, subidx, value, ec);
148  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "Write");
149 }
150 
151 template <class T>
152 typename ::std::enable_if<detail::IsCanopenBasic<T>::value>::type
153 Device::Write(uint16_t idx, uint8_t subidx, T value, ::std::error_code& ec) {
154  constexpr auto N = co_type_traits_T<T>::index;
155  uint32_t ac = 0;
156 
157  ::std::lock_guard<Impl_> lock(*impl_);
158  if (dnReq<N>(*impl_->dev, idx, subidx, value, &OnDnCon, &ac) == -1)
159  throw_errc("Write");
160 
161  if (ac)
162  ec = static_cast<SdoErrc>(ac);
163  else
164  ec.clear();
165 }
166 
167 template <class T>
168 typename ::std::enable_if<detail::IsCanopenArray<T>::value>::type
169 Device::Write(uint16_t idx, uint8_t subidx, const T& value) {
170  ::std::error_code ec;
171  Write(idx, subidx, value, ec);
172  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "Write");
173 }
174 
175 template <class T>
176 typename ::std::enable_if<detail::IsCanopenArray<T>::value>::type
177 Device::Write(uint16_t idx, uint8_t subidx, const T& value,
178  ::std::error_code& ec) {
179  constexpr auto N = co_type_traits_T<T>::index;
180  uint32_t ac = 0;
181 
182  ::std::lock_guard<Impl_> lock(*impl_);
183  if (dnReq<N>(*impl_->dev, idx, subidx, value, &OnDnCon, &ac) == -1)
184  throw_errc("Write");
185 
186  if (ac)
187  ec = static_cast<SdoErrc>(ac);
188  else
189  ec.clear();
190 }
191 
192 #ifndef DOXYGEN_SHOULD_SKIP_THIS
193 
194 // BOOLEAN
195 template bool Device::Read<bool>(uint16_t, uint8_t) const;
196 template bool Device::Read<bool>(uint16_t, uint8_t, ::std::error_code&) const;
197 template void Device::Write<bool>(uint16_t, uint8_t, bool);
198 template void Device::Write<bool>(uint16_t, uint8_t, bool, ::std::error_code&);
199 
200 // INTEGER8
201 template int8_t Device::Read<int8_t>(uint16_t, uint8_t) const;
202 template int8_t Device::Read<int8_t>(uint16_t, uint8_t,
203  ::std::error_code&) const;
204 template void Device::Write<int8_t>(uint16_t, uint8_t, int8_t);
205 template void Device::Write<int8_t>(uint16_t, uint8_t, int8_t,
206  ::std::error_code&);
207 
208 // INTEGER16
209 template int16_t Device::Read<int16_t>(uint16_t, uint8_t) const;
210 template int16_t Device::Read<int16_t>(uint16_t, uint8_t,
211  ::std::error_code&) const;
212 template void Device::Write<int16_t>(uint16_t, uint8_t, int16_t);
213 template void Device::Write<int16_t>(uint16_t, uint8_t, int16_t,
214  ::std::error_code&);
215 
216 // INTEGER32
217 template int32_t Device::Read<int32_t>(uint16_t, uint8_t) const;
218 template int32_t Device::Read<int32_t>(uint16_t, uint8_t,
219  ::std::error_code&) const;
220 template void Device::Write<int32_t>(uint16_t, uint8_t, int32_t);
221 template void Device::Write<int32_t>(uint16_t, uint8_t, int32_t,
222  ::std::error_code&);
223 
224 // UNSIGNED8
225 template uint8_t Device::Read<uint8_t>(uint16_t, uint8_t) const;
226 template uint8_t Device::Read<uint8_t>(uint16_t, uint8_t,
227  ::std::error_code&) const;
228 template void Device::Write<uint8_t>(uint16_t, uint8_t, uint8_t);
229 template void Device::Write<uint8_t>(uint16_t, uint8_t, uint8_t,
230  ::std::error_code&);
231 
232 // UNSIGNED16
233 template uint16_t Device::Read<uint16_t>(uint16_t, uint8_t) const;
234 template uint16_t Device::Read<uint16_t>(uint16_t, uint8_t,
235  ::std::error_code&) const;
236 template void Device::Write<uint16_t>(uint16_t, uint8_t, uint16_t);
237 template void Device::Write<uint16_t>(uint16_t, uint8_t, uint16_t,
238  ::std::error_code&);
239 
240 // UNSIGNED32
241 template uint32_t Device::Read<uint32_t>(uint16_t, uint8_t) const;
242 template uint32_t Device::Read<uint32_t>(uint16_t, uint8_t,
243  ::std::error_code&) const;
244 template void Device::Write<uint32_t>(uint16_t, uint8_t, uint32_t);
245 template void Device::Write<uint32_t>(uint16_t, uint8_t, uint32_t,
246  ::std::error_code&);
247 
248 // REAL32
249 template float Device::Read<float>(uint16_t, uint8_t) const;
250 template float Device::Read<float>(uint16_t, uint8_t, ::std::error_code&) const;
251 template void Device::Write<float>(uint16_t, uint8_t, float);
252 template void Device::Write<float>(uint16_t, uint8_t, float,
253  ::std::error_code&);
254 
255 // VISIBLE_STRING
256 template ::std::string Device::Read<::std::string>(uint16_t, uint8_t) const;
257 template ::std::string Device::Read<::std::string>(uint16_t, uint8_t,
258  ::std::error_code&) const;
259 template void Device::Write<::std::string>(uint16_t, uint8_t,
260  const ::std::string&);
261 template void Device::Write<::std::string>(uint16_t, uint8_t,
262  const ::std::string&,
263  ::std::error_code&);
264 
265 // OCTET_STRING
266 template ::std::vector<uint8_t> Device::Read<::std::vector<uint8_t>>(
267  uint16_t, uint8_t) const;
268 template ::std::vector<uint8_t> Device::Read<::std::vector<uint8_t>>(
269  uint16_t, uint8_t, ::std::error_code&) const;
270 template void Device::Write<::std::vector<uint8_t>>(
271  uint16_t, uint8_t, const ::std::vector<uint8_t>&);
272 template void Device::Write<::std::vector<uint8_t>>(
273  uint16_t, uint8_t, const ::std::vector<uint8_t>&, ::std::error_code&);
274 
275 // UNICODE_STRING
276 template ::std::basic_string<char16_t>
277  Device::Read<::std::basic_string<char16_t>>(uint16_t, uint8_t) const;
278 template ::std::basic_string<char16_t>
279 Device::Read<::std::basic_string<char16_t>>(uint16_t, uint8_t,
280  ::std::error_code&) const;
281 template void Device::Write<::std::basic_string<char16_t>>(
282  uint16_t, uint8_t, const ::std::basic_string<char16_t>&);
283 template void Device::Write<::std::basic_string<char16_t>>(
284  uint16_t, uint8_t, const ::std::basic_string<char16_t>&,
285  ::std::error_code&);
286 
287 // TIME_OF_DAY
288 // TIME_DIFFERENCE
289 // DOMAIN
290 // INTEGER24
291 
292 // REAL64
293 template double Device::Read<double>(uint16_t, uint8_t) const;
294 template double Device::Read<double>(uint16_t, uint8_t,
295  ::std::error_code&) const;
296 template void Device::Write<double>(uint16_t, uint8_t, double);
297 template void Device::Write<double>(uint16_t, uint8_t, double,
298  ::std::error_code&);
299 
300 // INTEGER40
301 // INTEGER48
302 // INTEGER56
303 
304 // INTEGER64
305 template int64_t Device::Read<int64_t>(uint16_t, uint8_t) const;
306 template int64_t Device::Read<int64_t>(uint16_t, uint8_t,
307  ::std::error_code&) const;
308 template void Device::Write<int64_t>(uint16_t, uint8_t, int64_t);
309 template void Device::Write<int64_t>(uint16_t, uint8_t, int64_t,
310  ::std::error_code&);
311 
312 // UNSIGNED24
313 // UNSIGNED40
314 // UNSIGNED48
315 // UNSIGNED56
316 
317 // UNSIGNED64
318 template uint64_t Device::Read<uint64_t>(uint16_t, uint8_t) const;
319 template uint64_t Device::Read<uint64_t>(uint16_t, uint8_t,
320  ::std::error_code&) const;
321 template void Device::Write<uint64_t>(uint16_t, uint8_t, uint64_t);
322 template void Device::Write<uint64_t>(uint16_t, uint8_t, uint64_t,
323  ::std::error_code&);
324 
325 #endif // DOXYGEN_SHOULD_SKIP_THIS
326 
327 void
328 Device::Write(uint16_t idx, uint8_t subidx, const char* value) {
329  ::std::error_code ec;
330  Write(idx, subidx, value, ec);
331  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "Write");
332 }
333 
334 void
335 Device::Write(uint16_t idx, uint8_t subidx, const char* value,
336  ::std::error_code& ec) {
337  Write(idx, subidx, value, ::std::char_traits<char>::length(value), ec);
338 }
339 
340 void
341 Device::Write(uint16_t idx, uint8_t subidx, const char16_t* value) {
342  ::std::error_code ec;
343  Write(idx, subidx, value, ec);
344  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "Write");
345 }
346 
347 void
348 Device::Write(uint16_t idx, uint8_t subidx, const char16_t* value,
349  ::std::error_code& ec) {
350  constexpr auto N = CO_DEFTYPE_UNICODE_STRING;
351  uint32_t ac = 0;
352 
353  ::std::lock_guard<Impl_> lock(*impl_);
354  // TODO: Prevent unnecessary copy.
355  if (dnReq<N>(*impl_->dev, idx, subidx, value, &OnDnCon, &ac) == -1)
356  throw_errc("Write");
357 
358  if (ac)
359  ec = static_cast<SdoErrc>(ac);
360  else
361  ec.clear();
362 }
363 
364 void
365 Device::Write(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n) {
366  ::std::error_code ec;
367  Write(idx, subidx, p, n, ec);
368  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "Write");
369 }
370 
371 void
372 Device::Write(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n,
373  ::std::error_code& ec) {
374  uint32_t ac = 0;
375 
376  ::std::lock_guard<Impl_> lock(*impl_);
377  if (dnReq(*impl_->dev, idx, subidx, p, n, &OnDnCon, &ac) == -1)
378  throw_errc("Write");
379 
380  if (ac)
381  ec = static_cast<SdoErrc>(ac);
382  else
383  ec.clear();
384 }
385 
386 CODev*
387 Device::dev() const noexcept {
388  return impl_->dev.get();
389 }
390 
391 const ::std::type_info&
392 Device::Type(uint16_t idx, uint8_t subidx) const {
393  ::std::error_code ec;
394  auto& ti = Type(idx, subidx, ec);
395  if (ec) throw SdoError(impl_->netid(), impl_->id(), idx, subidx, ec, "Type");
396  return ti;
397 }
398 
399 const ::std::type_info&
400 Device::Type(uint16_t idx, uint8_t subidx, ::std::error_code& ec) const {
401  auto obj = impl_->dev->find(idx);
402  if (!obj) {
403  ec = SdoErrc::NO_OBJ;
404  return typeid(void);
405  }
406 
407  auto sub = obj->find(subidx);
408  if (!sub) {
409  ec = SdoErrc::NO_SUB;
410  return typeid(void);
411  }
412 
413  ec.clear();
414  switch (sub->getType()) {
415  case CO_DEFTYPE_BOOLEAN:
416  return typeid(bool);
417  case CO_DEFTYPE_INTEGER8:
418  return typeid(int8_t);
420  return typeid(int16_t);
422  return typeid(int32_t);
424  return typeid(uint8_t);
426  return typeid(uint16_t);
428  return typeid(uint32_t);
429  case CO_DEFTYPE_REAL32:
430  return typeid(float);
432  return typeid(::std::string);
434  return typeid(::std::vector<uint8_t>);
436  return typeid(::std::basic_string<char16_t>);
437  // case CO_DEFTYPE_TIME_OF_DAY: ...
438  // case CO_DEFTYPE_TIME_DIFFERENCE: ...
439  case CO_DEFTYPE_DOMAIN:
440  return typeid(::std::vector<uint8_t>);
441  // case CO_DEFTYPE_INTEGER24: ...
442  case CO_DEFTYPE_REAL64:
443  return typeid(double);
444  // case CO_DEFTYPE_INTEGER40: ...
445  // case CO_DEFTYPE_INTEGER48: ...
446  // case CO_DEFTYPE_INTEGER56: ...
448  return typeid(int64_t);
449  // case CO_DEFTYPE_UNSIGNED24: ...
450  // case CO_DEFTYPE_UNSIGNED40: ...
451  // case CO_DEFTYPE_UNSIGNED48: ...
452  // case CO_DEFTYPE_UNSIGNED56: ...
454  return typeid(uint64_t);
455  default:
456  return typeid(void);
457  }
458 }
459 
460 template <class T>
461 typename ::std::enable_if<detail::IsCanopenType<T>::value, T>::type
462 Device::Get(uint16_t idx, uint8_t subidx) const {
463  ::std::error_code ec;
464  auto value = Get<T>(idx, subidx, ec);
465  if (ec) throw SdoError(impl_->netid(), impl_->id(), idx, subidx, ec, "Get");
466  return value;
467 }
468 
469 template <class T>
470 typename ::std::enable_if<detail::IsCanopenType<T>::value, T>::type
471 Device::Get(uint16_t idx, uint8_t subidx, ::std::error_code& ec) const {
472  constexpr auto N = co_type_traits_T<T>::index;
473 
474  auto obj = impl_->dev->find(idx);
475  if (!obj) {
476  ec = SdoErrc::NO_OBJ;
477  return T();
478  }
479 
480  auto sub = obj->find(subidx);
481  if (!sub) {
482  ec = SdoErrc::NO_SUB;
483  return T();
484  }
485 
486  if (!detail::IsCanopenSame(N, sub->getType())) {
487  ec = SdoErrc::TYPE_LEN;
488  return T();
489  }
490 
491  ec.clear();
492  // This is efficient, even for CANopen array values, since getVal<N>() returns
493  // a reference.
494  return sub->getVal<N>();
495 }
496 
497 template <class T>
498 typename ::std::enable_if<detail::IsCanopenBasic<T>::value>::type
499 Device::Set(uint16_t idx, uint8_t subidx, T value) {
500  ::std::error_code ec;
501  Set(idx, subidx, value, ec);
502  if (ec) throw SdoError(impl_->netid(), impl_->id(), idx, subidx, ec, "Set");
503 }
504 
505 template <class T>
506 typename ::std::enable_if<detail::IsCanopenBasic<T>::value>::type
507 Device::Set(uint16_t idx, uint8_t subidx, T value, ::std::error_code& ec) {
508  constexpr auto N = co_type_traits_T<T>::index;
509 
510  impl_->Set<N>(idx, subidx, &value, sizeof(value), ec);
511 }
512 
513 template <class T>
514 typename ::std::enable_if<detail::IsCanopenArray<T>::value>::type
515 Device::Set(uint16_t idx, uint8_t subidx, const T& value) {
516  ::std::error_code ec;
517  Set(idx, subidx, value, ec);
518  if (ec) throw SdoError(impl_->netid(), impl_->id(), idx, subidx, ec, "Set");
519 }
520 
521 template <class T>
522 typename ::std::enable_if<detail::IsCanopenArray<T>::value>::type
523 Device::Set(uint16_t idx, uint8_t subidx, const T& value,
524  ::std::error_code& ec) {
525  impl_->Set(idx, subidx, value, ec);
526 }
527 
528 #ifndef DOXYGEN_SHOULD_SKIP_THIS
529 
530 // BOOLEAN
531 template bool Device::Get<bool>(uint16_t, uint8_t) const;
532 template bool Device::Get<bool>(uint16_t, uint8_t, ::std::error_code&) const;
533 template void Device::Set<bool>(uint16_t, uint8_t, bool);
534 template void Device::Set<bool>(uint16_t, uint8_t, bool, ::std::error_code&);
535 
536 // INTEGER8
537 template int8_t Device::Get<int8_t>(uint16_t, uint8_t) const;
538 template int8_t Device::Get<int8_t>(uint16_t, uint8_t,
539  ::std::error_code&) const;
540 template void Device::Set<int8_t>(uint16_t, uint8_t, int8_t);
541 template void Device::Set<int8_t>(uint16_t, uint8_t, int8_t,
542  ::std::error_code&);
543 
544 // INTEGER16
545 template int16_t Device::Get<int16_t>(uint16_t, uint8_t) const;
546 template int16_t Device::Get<int16_t>(uint16_t, uint8_t,
547  ::std::error_code&) const;
548 template void Device::Set<int16_t>(uint16_t, uint8_t, int16_t);
549 template void Device::Set<int16_t>(uint16_t, uint8_t, int16_t,
550  ::std::error_code&);
551 
552 // INTEGER32
553 template int32_t Device::Get<int32_t>(uint16_t, uint8_t) const;
554 template int32_t Device::Get<int32_t>(uint16_t, uint8_t,
555  ::std::error_code&) const;
556 template void Device::Set<int32_t>(uint16_t, uint8_t, int32_t);
557 template void Device::Set<int32_t>(uint16_t, uint8_t, int32_t,
558  ::std::error_code&);
559 
560 // UNSIGNED8
561 template uint8_t Device::Get<uint8_t>(uint16_t, uint8_t) const;
562 template uint8_t Device::Get<uint8_t>(uint16_t, uint8_t,
563  ::std::error_code&) const;
564 template void Device::Set<uint8_t>(uint16_t, uint8_t, uint8_t);
565 template void Device::Set<uint8_t>(uint16_t, uint8_t, uint8_t,
566  ::std::error_code&);
567 
568 // UNSIGNED16
569 template uint16_t Device::Get<uint16_t>(uint16_t, uint8_t) const;
570 template uint16_t Device::Get<uint16_t>(uint16_t, uint8_t,
571  ::std::error_code&) const;
572 template void Device::Set<uint16_t>(uint16_t, uint8_t, uint16_t);
573 template void Device::Set<uint16_t>(uint16_t, uint8_t, uint16_t,
574  ::std::error_code&);
575 
576 // UNSIGNED32
577 template uint32_t Device::Get<uint32_t>(uint16_t, uint8_t) const;
578 template uint32_t Device::Get<uint32_t>(uint16_t, uint8_t,
579  ::std::error_code&) const;
580 template void Device::Set<uint32_t>(uint16_t, uint8_t, uint32_t);
581 template void Device::Set<uint32_t>(uint16_t, uint8_t, uint32_t,
582  ::std::error_code&);
583 
584 // REAL32
585 template float Device::Get<float>(uint16_t, uint8_t) const;
586 template float Device::Get<float>(uint16_t, uint8_t, ::std::error_code&) const;
587 template void Device::Set<float>(uint16_t, uint8_t, float);
588 template void Device::Set<float>(uint16_t, uint8_t, float, ::std::error_code&);
589 
590 // VISIBLE_STRING
591 template ::std::string Device::Get<::std::string>(uint16_t, uint8_t) const;
592 template ::std::string Device::Get<::std::string>(uint16_t, uint8_t,
593  ::std::error_code&) const;
594 template void Device::Set<::std::string>(uint16_t, uint8_t,
595  const ::std::string&);
596 template void Device::Set<::std::string>(uint16_t, uint8_t,
597  const ::std::string&,
598  ::std::error_code&);
599 
600 // OCTET_STRING
601 template ::std::vector<uint8_t> Device::Get<::std::vector<uint8_t>>(
602  uint16_t, uint8_t) const;
603 template ::std::vector<uint8_t> Device::Get<::std::vector<uint8_t>>(
604  uint16_t, uint8_t, ::std::error_code&) const;
605 template void Device::Set<::std::vector<uint8_t>>(
606  uint16_t, uint8_t, const ::std::vector<uint8_t>&);
607 template void Device::Set<::std::vector<uint8_t>>(uint16_t, uint8_t,
608  const ::std::vector<uint8_t>&,
609  ::std::error_code&);
610 
611 // UNICODE_STRING
612 template ::std::basic_string<char16_t>
613  Device::Get<::std::basic_string<char16_t>>(uint16_t, uint8_t) const;
614 template ::std::basic_string<char16_t>
615 Device::Get<::std::basic_string<char16_t>>(uint16_t, uint8_t,
616  ::std::error_code&) const;
617 template void Device::Set<::std::basic_string<char16_t>>(
618  uint16_t, uint8_t, const ::std::basic_string<char16_t>&);
619 template void Device::Set<::std::basic_string<char16_t>>(
620  uint16_t, uint8_t, const ::std::basic_string<char16_t>&,
621  ::std::error_code&);
622 
623 // TIME_OF_DAY
624 // TIME_DIFFERENCE
625 // DOMAIN
626 // INTEGER24
627 
628 // REAL64
629 template double Device::Get<double>(uint16_t, uint8_t) const;
630 template double Device::Get<double>(uint16_t, uint8_t,
631  ::std::error_code&) const;
632 template void Device::Set<double>(uint16_t, uint8_t, double);
633 template void Device::Set<double>(uint16_t, uint8_t, double,
634  ::std::error_code&);
635 
636 // INTEGER40
637 // INTEGER48
638 // INTEGER56
639 
640 // INTEGER64
641 template int64_t Device::Get<int64_t>(uint16_t, uint8_t) const;
642 template int64_t Device::Get<int64_t>(uint16_t, uint8_t,
643  ::std::error_code&) const;
644 template void Device::Set<int64_t>(uint16_t, uint8_t, int64_t);
645 template void Device::Set<int64_t>(uint16_t, uint8_t, int64_t,
646  ::std::error_code&);
647 
648 // UNSIGNED24
649 // UNSIGNED40
650 // UNSIGNED48
651 // UNSIGNED56
652 
653 // UNSIGNED64
654 template uint64_t Device::Get<uint64_t>(uint16_t, uint8_t) const;
655 template uint64_t Device::Get<uint64_t>(uint16_t, uint8_t,
656  ::std::error_code&) const;
657 template void Device::Set<uint64_t>(uint16_t, uint8_t, uint64_t);
658 template void Device::Set<uint64_t>(uint16_t, uint8_t, uint64_t,
659  ::std::error_code&);
660 
661 #endif // DOXYGEN_SHOULD_SKIP_THIS
662 
663 void
664 Device::Set(uint16_t idx, uint8_t subidx, const char* value) {
665  ::std::error_code ec;
666  Set(idx, subidx, value, ec);
667  if (ec) throw SdoError(impl_->netid(), impl_->id(), idx, subidx, ec, "Set");
668 }
669 
670 void
671 Device::Set(uint16_t idx, uint8_t subidx, const char* value,
672  ::std::error_code& ec) {
673  impl_->Set<CO_DEFTYPE_VISIBLE_STRING>(idx, subidx, value, 0, ec);
674 }
675 
676 void
677 Device::Set(uint16_t idx, uint8_t subidx, const char16_t* value) {
678  ::std::error_code ec;
679  Set(idx, subidx, value, ec);
680  if (ec) throw SdoError(impl_->netid(), impl_->id(), idx, subidx, ec, "Set");
681 }
682 
683 void
684 Device::Set(uint16_t idx, uint8_t subidx, const char16_t* value,
685  ::std::error_code& ec) {
686  impl_->Set<CO_DEFTYPE_UNICODE_STRING>(idx, subidx, value, 0, ec);
687 }
688 
689 void
690 Device::Set(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n) {
691  ::std::error_code ec;
692  Set(idx, subidx, p, n, ec);
693  if (ec) throw SdoError(impl_->netid(), impl_->id(), idx, subidx, ec, "Set");
694 }
695 
696 void
697 Device::Set(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n,
698  ::std::error_code& ec) {
699  impl_->Set<CO_DEFTYPE_OCTET_STRING>(idx, subidx, p, n, ec);
700 }
701 
702 Device::Impl_::Impl_(const ::std::string& dcf_txt, const ::std::string& dcf_bin,
703  uint8_t id, BasicLockable* mutex_)
704  : mutex(mutex_), dev(make_unique_c<CODev>(dcf_txt.c_str())) {
705  if (!dcf_bin.empty() && dev->readDCF(nullptr, nullptr, dcf_bin.c_str()) == -1)
706  throw_errc("Device");
707 
708  if (id != 0xff && dev->setId(id) == -1) throw_errc("Device");
709 }
710 
711 void
712 Device::Impl_::Set(uint16_t idx, uint8_t subidx, const ::std::string& value,
713  ::std::error_code& ec) {
714  Set<CO_DEFTYPE_VISIBLE_STRING>(idx, subidx, value.c_str(), 0, ec);
715 }
716 
717 void
718 Device::Impl_::Set(uint16_t idx, uint8_t subidx,
719  const ::std::vector<uint8_t>& value, ::std::error_code& ec) {
720  Set<CO_DEFTYPE_OCTET_STRING>(idx, subidx, value.data(), value.size(), ec);
721 }
722 
723 void
724 Device::Impl_::Set(uint16_t idx, uint8_t subidx,
725  const ::std::basic_string<char16_t>& value,
726  ::std::error_code& ec) {
727  Set<CO_DEFTYPE_UNICODE_STRING>(idx, subidx, value.c_str(), 0, ec);
728 }
729 
730 template <uint16_t N>
731 void
732 Device::Impl_::Set(uint16_t idx, uint8_t subidx, const void* p, ::std::size_t n,
733  ::std::error_code& ec) {
734  auto obj = dev->find(idx);
735  if (!obj) {
736  ec = SdoErrc::NO_OBJ;
737  return;
738  }
739 
740  auto sub = obj->find(subidx);
741  if (!sub) {
742  ec = SdoErrc::NO_SUB;
743  return;
744  }
745 
746  if (!detail::IsCanopenSame(N, sub->getType())) {
747  ec = SdoErrc::TYPE_LEN;
748  return;
749  }
750 
751  ec.clear();
752  sub->setVal(p, n);
753 }
754 
755 } // namespace canopen
756 
757 } // namespace lely
This header file is part of the C++ CANopen application library; it contains the CANopen device descr...
typename ::std::enable_if< detail::IsCanopenType< T >::value, T >::type Get(uint16_t idx, uint8_t subidx) const
Reads the value of a sub-object.
#define CO_DEFTYPE_VISIBLE_STRING
The data type (and object index) of an array of visible characters.
Definition: type.h:56
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
#define CO_DEFTYPE_DOMAIN
The data type (and object index) of an arbitrary large block of data.
Definition: type.h:77
virtual void unlock()=0
Releases the lock held by the execution agent. Throws no exceptions.
virtual void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
Definition: device.cpp:47
A class template mapping CANopen types to C++ types.
Definition: type.hpp:59
An opaque CANopen Client-SDO service type.
Definition: csdo.hpp:156
An opaque CANopen device type.
Definition: dev.hpp:76
typename ::std::enable_if< detail::IsCanopenType< T >::value, T >::type Read(uint16_t idx, uint8_t subidx) const
Submits an SDO upload request to the local object dictionary.
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
uint8_t netid() const noexcept
Returns the network-ID.
Definition: device.cpp:87
#define CO_DEFTYPE_INTEGER64
The data type (and object index) of a 64-bit signed integer.
Definition: type.h:95
#define CO_DEFTYPE_REAL32
The data type (and object index) of a 32-bit IEEE-754 floating-point number.
Definition: type.h:53
Sub-index does not exist.
#define CO_DEFTYPE_INTEGER8
The data type (and object index) of an 8-bit signed integer.
Definition: type.h:35
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
Device(const ::std::string &dcf_txt, const ::std::string &dcf_bin="", uint8_t id=0xff, BasicLockable *mutex=nullptr)
Creates a new CANopen device description.
Definition: device.cpp:78
#define CO_DEFTYPE_UNICODE_STRING
The data type (and object index) of an array of (16-bit) Unicode characters.
Definition: type.h:62
SdoErrc
The SDO abort codes.
Definition: sdo_error.hpp:37
This header file is part of the CANopen library; it contains the C++ interface of the object dictiona...
virtual void lock()=0
Blocks until a lock can be obtained for the current execution agent (thread, process, task).
const ::std::type_info & Type(uint16_t idx, uint8_t subidx) const
Returns the type of a sub-object.
Definition: device.cpp:392
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
Data type does not match, length of service parameter does not match.
#define CO_DEFTYPE_INTEGER16
The data type (and object index) of a 16-bit signed integer.
Definition: type.h:38
An abstract interface conforming to the BasicLockable concept.
Definition: coapp.hpp:40
This is the internal header file of the C++ CANopen application library.
#define CO_DEFTYPE_OCTET_STRING
The data type (and object index) of an array of octets.
Definition: type.h:59
#define CO_DEFTYPE_UNSIGNED64
The data type (and object index) of a 64-bit unsigned integer.
Definition: type.h:110
This header file is part of the CANopen library; it contains the C++ interface of the Electronic Data...
Object does not exist in the object dictionary.
#define CO_DEFTYPE_REAL64
The data type (and object index) of a 64-bit IEEE-754 floating-point number.
Definition: type.h:83
typename ::std::enable_if< detail::IsCanopenBasic< T >::value >::type Write(uint16_t idx, uint8_t subidx, T value)
Submits an SDO download request to the local object dictionary.
virtual void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process, task).
Definition: device.cpp:43
The internal implementation of the CANopen device description.
Definition: device.cpp:38
CODev * dev() const noexcept
Returns a pointer to the internal CANopen device from <lely/co/dev.hpp>.
Definition: device.cpp:387
The CANopen device description.
Definition: device.hpp:42
This header file is part of the CANopen library; it contains the C++ interface of the Client-SDO decl...
Global namespace for the Lely Industries N.V. libraries.
Definition: buf.hpp:32
#define CO_DEFTYPE_INTEGER32
The data type (and object index) of a 32-bit signed integer.
Definition: type.h:41
uint8_t id() const noexcept
Returns the node-ID.
Definition: device.cpp:94
typename ::std::enable_if< detail::IsCanopenBasic< T >::value >::type Set(uint16_t idx, uint8_t subidx, T value)
Writes a CANopen basic value to a sub-object.
The type of exception thrown when an SDO abort code is received.
Definition: sdo_error.hpp:116
#define CO_DEFTYPE_BOOLEAN
The data type (and object index) of a boolean truth value.
Definition: type.h:32
bool IsCanopenSame(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...