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
33namespace lely {
34
35namespace canopen {
36
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
78Device::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
82Device& Device::operator=(Device&&) = default;
83
84Device::~Device() = default;
85
86uint8_t
87Device::netid() const noexcept {
88 ::std::lock_guard<Impl_> lock(*impl_);
89
90 return impl_->netid();
91}
92
93uint8_t
94Device::id() const noexcept {
95 ::std::lock_guard<Impl_> lock(*impl_);
96
97 return impl_->id();
98}
99
100namespace {
101
102void
103OnDnCon(COCSDO*, uint16_t, uint8_t, uint32_t ac, void* data) noexcept {
104 *static_cast<uint32_t*>(data) = ac;
105}
106
107template <class T>
108void
109OnUpCon(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
116template <class T>
117typename ::std::enable_if<detail::IsCanopenType<T>::value, T>::type
118Device::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
125template <class T>
126typename ::std::enable_if<detail::IsCanopenType<T>::value, T>::type
127Device::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
143template <class T>
144typename ::std::enable_if<detail::IsCanopenBasic<T>::value>::type
145Device::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
151template <class T>
152typename ::std::enable_if<detail::IsCanopenBasic<T>::value>::type
153Device::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
167template <class T>
168typename ::std::enable_if<detail::IsCanopenArray<T>::value>::type
169Device::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
175template <class T>
176typename ::std::enable_if<detail::IsCanopenArray<T>::value>::type
177Device::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
195template bool Device::Read<bool>(uint16_t, uint8_t) const;
196template bool Device::Read<bool>(uint16_t, uint8_t, ::std::error_code&) const;
197template void Device::Write<bool>(uint16_t, uint8_t, bool);
198template void Device::Write<bool>(uint16_t, uint8_t, bool, ::std::error_code&);
199
200// INTEGER8
201template int8_t Device::Read<int8_t>(uint16_t, uint8_t) const;
202template int8_t Device::Read<int8_t>(uint16_t, uint8_t,
203 ::std::error_code&) const;
204template void Device::Write<int8_t>(uint16_t, uint8_t, int8_t);
205template void Device::Write<int8_t>(uint16_t, uint8_t, int8_t,
206 ::std::error_code&);
207
208// INTEGER16
209template int16_t Device::Read<int16_t>(uint16_t, uint8_t) const;
210template int16_t Device::Read<int16_t>(uint16_t, uint8_t,
211 ::std::error_code&) const;
212template void Device::Write<int16_t>(uint16_t, uint8_t, int16_t);
213template void Device::Write<int16_t>(uint16_t, uint8_t, int16_t,
214 ::std::error_code&);
215
216// INTEGER32
217template int32_t Device::Read<int32_t>(uint16_t, uint8_t) const;
218template int32_t Device::Read<int32_t>(uint16_t, uint8_t,
219 ::std::error_code&) const;
220template void Device::Write<int32_t>(uint16_t, uint8_t, int32_t);
221template void Device::Write<int32_t>(uint16_t, uint8_t, int32_t,
222 ::std::error_code&);
223
224// UNSIGNED8
225template uint8_t Device::Read<uint8_t>(uint16_t, uint8_t) const;
226template uint8_t Device::Read<uint8_t>(uint16_t, uint8_t,
227 ::std::error_code&) const;
228template void Device::Write<uint8_t>(uint16_t, uint8_t, uint8_t);
229template void Device::Write<uint8_t>(uint16_t, uint8_t, uint8_t,
230 ::std::error_code&);
231
232// UNSIGNED16
233template uint16_t Device::Read<uint16_t>(uint16_t, uint8_t) const;
234template uint16_t Device::Read<uint16_t>(uint16_t, uint8_t,
235 ::std::error_code&) const;
236template void Device::Write<uint16_t>(uint16_t, uint8_t, uint16_t);
237template void Device::Write<uint16_t>(uint16_t, uint8_t, uint16_t,
238 ::std::error_code&);
239
240// UNSIGNED32
241template uint32_t Device::Read<uint32_t>(uint16_t, uint8_t) const;
242template uint32_t Device::Read<uint32_t>(uint16_t, uint8_t,
243 ::std::error_code&) const;
244template void Device::Write<uint32_t>(uint16_t, uint8_t, uint32_t);
245template void Device::Write<uint32_t>(uint16_t, uint8_t, uint32_t,
246 ::std::error_code&);
247
248// REAL32
249template float Device::Read<float>(uint16_t, uint8_t) const;
250template float Device::Read<float>(uint16_t, uint8_t, ::std::error_code&) const;
251template void Device::Write<float>(uint16_t, uint8_t, float);
252template void Device::Write<float>(uint16_t, uint8_t, float,
253 ::std::error_code&);
254
255// VISIBLE_STRING
256template ::std::string Device::Read<::std::string>(uint16_t, uint8_t) const;
257template ::std::string Device::Read<::std::string>(uint16_t, uint8_t,
258 ::std::error_code&) const;
259template void Device::Write<::std::string>(uint16_t, uint8_t,
260 const ::std::string&);
261template void Device::Write<::std::string>(uint16_t, uint8_t,
262 const ::std::string&,
263 ::std::error_code&);
264
265// OCTET_STRING
266template ::std::vector<uint8_t> Device::Read<::std::vector<uint8_t>>(
267 uint16_t, uint8_t) const;
268template ::std::vector<uint8_t> Device::Read<::std::vector<uint8_t>>(
269 uint16_t, uint8_t, ::std::error_code&) const;
270template void Device::Write<::std::vector<uint8_t>>(
271 uint16_t, uint8_t, const ::std::vector<uint8_t>&);
272template void Device::Write<::std::vector<uint8_t>>(
273 uint16_t, uint8_t, const ::std::vector<uint8_t>&, ::std::error_code&);
274
275// UNICODE_STRING
276template ::std::basic_string<char16_t>
277 Device::Read<::std::basic_string<char16_t>>(uint16_t, uint8_t) const;
278template ::std::basic_string<char16_t>
279Device::Read<::std::basic_string<char16_t>>(uint16_t, uint8_t,
280 ::std::error_code&) const;
281template void Device::Write<::std::basic_string<char16_t>>(
282 uint16_t, uint8_t, const ::std::basic_string<char16_t>&);
283template 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
293template double Device::Read<double>(uint16_t, uint8_t) const;
294template double Device::Read<double>(uint16_t, uint8_t,
295 ::std::error_code&) const;
296template void Device::Write<double>(uint16_t, uint8_t, double);
297template void Device::Write<double>(uint16_t, uint8_t, double,
298 ::std::error_code&);
299
300// INTEGER40
301// INTEGER48
302// INTEGER56
303
304// INTEGER64
305template int64_t Device::Read<int64_t>(uint16_t, uint8_t) const;
306template int64_t Device::Read<int64_t>(uint16_t, uint8_t,
307 ::std::error_code&) const;
308template void Device::Write<int64_t>(uint16_t, uint8_t, int64_t);
309template 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
318template uint64_t Device::Read<uint64_t>(uint16_t, uint8_t) const;
319template uint64_t Device::Read<uint64_t>(uint16_t, uint8_t,
320 ::std::error_code&) const;
321template void Device::Write<uint64_t>(uint16_t, uint8_t, uint64_t);
322template void Device::Write<uint64_t>(uint16_t, uint8_t, uint64_t,
323 ::std::error_code&);
324
325#endif // DOXYGEN_SHOULD_SKIP_THIS
326
327void
328Device::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
334void
335Device::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
340void
341Device::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
347void
348Device::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
364void
365Device::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
371void
372Device::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
386CODev*
387Device::dev() const noexcept {
388 return impl_->dev.get();
389}
390
391const ::std::type_info&
392Device::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
399const ::std::type_info&
400Device::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()) {
416 return typeid(bool);
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);
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: ...
440 return typeid(::std::vector<uint8_t>);
441 // case CO_DEFTYPE_INTEGER24: ...
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
460template <class T>
461typename ::std::enable_if<detail::IsCanopenType<T>::value, T>::type
462Device::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
469template <class T>
470typename ::std::enable_if<detail::IsCanopenType<T>::value, T>::type
471Device::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())) {
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
497template <class T>
498typename ::std::enable_if<detail::IsCanopenBasic<T>::value>::type
499Device::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
505template <class T>
506typename ::std::enable_if<detail::IsCanopenBasic<T>::value>::type
507Device::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
513template <class T>
514typename ::std::enable_if<detail::IsCanopenArray<T>::value>::type
515Device::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
521template <class T>
522typename ::std::enable_if<detail::IsCanopenArray<T>::value>::type
523Device::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
531template bool Device::Get<bool>(uint16_t, uint8_t) const;
532template bool Device::Get<bool>(uint16_t, uint8_t, ::std::error_code&) const;
533template void Device::Set<bool>(uint16_t, uint8_t, bool);
534template void Device::Set<bool>(uint16_t, uint8_t, bool, ::std::error_code&);
535
536// INTEGER8
537template int8_t Device::Get<int8_t>(uint16_t, uint8_t) const;
538template int8_t Device::Get<int8_t>(uint16_t, uint8_t,
539 ::std::error_code&) const;
540template void Device::Set<int8_t>(uint16_t, uint8_t, int8_t);
541template void Device::Set<int8_t>(uint16_t, uint8_t, int8_t,
542 ::std::error_code&);
543
544// INTEGER16
545template int16_t Device::Get<int16_t>(uint16_t, uint8_t) const;
546template int16_t Device::Get<int16_t>(uint16_t, uint8_t,
547 ::std::error_code&) const;
548template void Device::Set<int16_t>(uint16_t, uint8_t, int16_t);
549template void Device::Set<int16_t>(uint16_t, uint8_t, int16_t,
550 ::std::error_code&);
551
552// INTEGER32
553template int32_t Device::Get<int32_t>(uint16_t, uint8_t) const;
554template int32_t Device::Get<int32_t>(uint16_t, uint8_t,
555 ::std::error_code&) const;
556template void Device::Set<int32_t>(uint16_t, uint8_t, int32_t);
557template void Device::Set<int32_t>(uint16_t, uint8_t, int32_t,
558 ::std::error_code&);
559
560// UNSIGNED8
561template uint8_t Device::Get<uint8_t>(uint16_t, uint8_t) const;
562template uint8_t Device::Get<uint8_t>(uint16_t, uint8_t,
563 ::std::error_code&) const;
564template void Device::Set<uint8_t>(uint16_t, uint8_t, uint8_t);
565template void Device::Set<uint8_t>(uint16_t, uint8_t, uint8_t,
566 ::std::error_code&);
567
568// UNSIGNED16
569template uint16_t Device::Get<uint16_t>(uint16_t, uint8_t) const;
570template uint16_t Device::Get<uint16_t>(uint16_t, uint8_t,
571 ::std::error_code&) const;
572template void Device::Set<uint16_t>(uint16_t, uint8_t, uint16_t);
573template void Device::Set<uint16_t>(uint16_t, uint8_t, uint16_t,
574 ::std::error_code&);
575
576// UNSIGNED32
577template uint32_t Device::Get<uint32_t>(uint16_t, uint8_t) const;
578template uint32_t Device::Get<uint32_t>(uint16_t, uint8_t,
579 ::std::error_code&) const;
580template void Device::Set<uint32_t>(uint16_t, uint8_t, uint32_t);
581template void Device::Set<uint32_t>(uint16_t, uint8_t, uint32_t,
582 ::std::error_code&);
583
584// REAL32
585template float Device::Get<float>(uint16_t, uint8_t) const;
586template float Device::Get<float>(uint16_t, uint8_t, ::std::error_code&) const;
587template void Device::Set<float>(uint16_t, uint8_t, float);
588template void Device::Set<float>(uint16_t, uint8_t, float, ::std::error_code&);
589
590// VISIBLE_STRING
591template ::std::string Device::Get<::std::string>(uint16_t, uint8_t) const;
592template ::std::string Device::Get<::std::string>(uint16_t, uint8_t,
593 ::std::error_code&) const;
594template void Device::Set<::std::string>(uint16_t, uint8_t,
595 const ::std::string&);
596template void Device::Set<::std::string>(uint16_t, uint8_t,
597 const ::std::string&,
598 ::std::error_code&);
599
600// OCTET_STRING
601template ::std::vector<uint8_t> Device::Get<::std::vector<uint8_t>>(
602 uint16_t, uint8_t) const;
603template ::std::vector<uint8_t> Device::Get<::std::vector<uint8_t>>(
604 uint16_t, uint8_t, ::std::error_code&) const;
605template void Device::Set<::std::vector<uint8_t>>(
606 uint16_t, uint8_t, const ::std::vector<uint8_t>&);
607template 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
612template ::std::basic_string<char16_t>
613 Device::Get<::std::basic_string<char16_t>>(uint16_t, uint8_t) const;
614template ::std::basic_string<char16_t>
615Device::Get<::std::basic_string<char16_t>>(uint16_t, uint8_t,
616 ::std::error_code&) const;
617template void Device::Set<::std::basic_string<char16_t>>(
618 uint16_t, uint8_t, const ::std::basic_string<char16_t>&);
619template 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
629template double Device::Get<double>(uint16_t, uint8_t) const;
630template double Device::Get<double>(uint16_t, uint8_t,
631 ::std::error_code&) const;
632template void Device::Set<double>(uint16_t, uint8_t, double);
633template void Device::Set<double>(uint16_t, uint8_t, double,
634 ::std::error_code&);
635
636// INTEGER40
637// INTEGER48
638// INTEGER56
639
640// INTEGER64
641template int64_t Device::Get<int64_t>(uint16_t, uint8_t) const;
642template int64_t Device::Get<int64_t>(uint16_t, uint8_t,
643 ::std::error_code&) const;
644template void Device::Set<int64_t>(uint16_t, uint8_t, int64_t);
645template 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
654template uint64_t Device::Get<uint64_t>(uint16_t, uint8_t) const;
655template uint64_t Device::Get<uint64_t>(uint16_t, uint8_t,
656 ::std::error_code&) const;
657template void Device::Set<uint64_t>(uint16_t, uint8_t, uint64_t);
658template void Device::Set<uint64_t>(uint16_t, uint8_t, uint64_t,
659 ::std::error_code&);
660
661#endif // DOXYGEN_SHOULD_SKIP_THIS
662
663void
664Device::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
670void
671Device::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
676void
677Device::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
683void
684Device::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
689void
690Device::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
696void
697Device::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
702Device::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
711void
712Device::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
717void
718Device::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
723void
724Device::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
730template <uint16_t N>
731void
732Device::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())) {
748 return;
749 }
750
751 ec.clear();
752 sub->setVal(p, n);
753}
754
755} // namespace canopen
756
757} // namespace lely
An opaque CANopen Client-SDO service type.
Definition: csdo.hpp:156
An opaque CANopen device type.
Definition: dev.hpp:76
An abstract interface conforming to the BasicLockable concept.
Definition: coapp.hpp:40
virtual void unlock()=0
Releases the lock held by the execution agent. Throws no exceptions.
virtual void lock()=0
Blocks until a lock can be obtained for the current execution agent (thread, process,...
The CANopen device description.
Definition: device.hpp:42
uint8_t netid() const noexcept
Returns the network-ID.
Definition: device.cpp:87
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.
Definition: device.cpp:462
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
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.
Definition: device.cpp:118
const ::std::type_info & Type(uint16_t idx, uint8_t subidx) const
Returns the type of a sub-object.
Definition: device.cpp:392
CODev * dev() const noexcept
Returns a pointer to the internal CANopen device from <lely/co/dev.hpp>.
Definition: device.cpp:387
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.
Definition: device.cpp:499
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.
Definition: device.cpp:145
uint8_t id() const noexcept
Returns the node-ID.
Definition: device.cpp:94
The type of exception thrown when an SDO abort code is received.
Definition: sdo_error.hpp:116
This header file is part of the CANopen library; it contains the C++ interface of the Client-SDO decl...
This header file is part of the CANopen library; it contains the C++ interface of the Electronic Data...
This header file is part of the C++ CANopen application library; it contains the CANopen device descr...
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.
SdoErrc
The SDO abort codes.
Definition: sdo_error.hpp:37
@ NO_SUB
Sub-index does not exist.
@ TYPE_LEN
Data type does not match, length of service parameter does not match.
@ NO_OBJ
Object does not exist in the object dictionary.
Global namespace for the Lely Industries N.V. libraries.
Definition: buf.hpp:32
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
This header file is part of the CANopen library; it contains the C++ interface of the object dictiona...
This is the internal header file of the C++ CANopen application library.
The internal implementation of the CANopen device description.
Definition: device.cpp:38
virtual void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: device.cpp:43
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
#define CO_DEFTYPE_UNICODE_STRING
The data type (and object index) of an array of (16-bit) Unicode characters.
Definition: type.h:62
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
#define CO_DEFTYPE_VISIBLE_STRING
The data type (and object index) of an array of visible characters.
Definition: type.h:56
#define CO_DEFTYPE_UNSIGNED64
The data type (and object index) of a 64-bit unsigned integer.
Definition: type.h:110
#define CO_DEFTYPE_INTEGER8
The data type (and object index) of an 8-bit signed integer.
Definition: type.h:35
#define CO_DEFTYPE_DOMAIN
The data type (and object index) of an arbitrary large block of data.
Definition: type.h:77
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
#define CO_DEFTYPE_REAL64
The data type (and object index) of a 64-bit IEEE-754 floating-point number.
Definition: type.h:83
#define CO_DEFTYPE_BOOLEAN
The data type (and object index) of a boolean truth value.
Definition: type.h:32
#define CO_DEFTYPE_INTEGER32
The data type (and object index) of a 32-bit signed integer.
Definition: type.h:41
#define CO_DEFTYPE_INTEGER64
The data type (and object index) of a 64-bit signed integer.
Definition: type.h:95
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
#define CO_DEFTYPE_INTEGER16
The data type (and object index) of a 16-bit signed integer.
Definition: type.h:38
#define CO_DEFTYPE_OCTET_STRING
The data type (and object index) of an array of octets.
Definition: type.h:59
#define CO_DEFTYPE_REAL32
The data type (and object index) of a 32-bit IEEE-754 floating-point number.
Definition: type.h:53