Lely core libraries 2.3.4
lss_master.cpp
Go to the documentation of this file.
1
24#include "coapp.hpp"
25
26#if !LELY_NO_CO_LSS
27
29
30#include <lely/co/lss.h>
31#include <lely/co/nmt.h>
32
33#include <algorithm>
34#include <limits>
35
36#include <cassert>
37
38namespace lely {
39
40namespace canopen {
41
43 Impl_(LssMaster* self, ev_exec_t* exec, Node& node,
45 virtual ~Impl_();
46
47 void
48 lock() final {
49 self->lock();
50 }
51
52 void
53 unlock() final {
54 self->unlock();
55 }
56
57 void OnLssReq(co_nmt_t*, co_lss_t* lss) noexcept;
58
59 void Submit(detail::LssRequestBase& req);
60 ::std::size_t Cancel(detail::LssRequestBase* req, ::std::error_code ec);
61 ::std::size_t Abort(detail::LssRequestBase* req);
62
63 bool Pop(detail::LssRequestBase* req, sllist& queue);
64
65 // The functions called by the OnRequest() methods to initiate an LSS request.
66 void OnSwitch(detail::LssSwitchRequestBase& req) noexcept;
67 void OnSwitchSelective(detail::LssSwitchSelectiveRequestBase& req) noexcept;
68 void OnSetId(detail::LssSetIdRequestBase& req) noexcept;
69 void OnSetBitrate(detail::LssSetBitrateRequestBase& req) noexcept;
70 void OnSwitchBitrate(detail::LssSwitchBitrateRequestBase& req) noexcept;
71 void OnStore(detail::LssStoreRequestBase& req) noexcept;
72 void OnGetVendorId(detail::LssGetVendorIdRequestBase& req) noexcept;
73 void OnGetProductCode(detail::LssGetProductCodeRequestBase& req) noexcept;
74 void OnGetRevision(detail::LssGetRevisionRequestBase& req) noexcept;
75 void OnGetSerialNr(detail::LssGetSerialNrRequestBase& req) noexcept;
76 void OnGetId(detail::LssGetIdRequestBase& req) noexcept;
77 void OnIdNonConfig(detail::LssIdNonConfigRequestBase& req) noexcept;
78 void OnSlowscan(detail::LssSlowscanRequestBase& req) noexcept;
79 void OnFastscan(detail::LssFastscanRequestBase& req) noexcept;
80
81 // The indication functions called by the LSS master service when an LSS
82 // request completes. See the function type definitions in <lely/co/lss.h> for
83 // more information.
84 void OnCsInd(co_lss_t*, uint8_t cs) noexcept;
85 void OnErrInd(co_lss_t*, uint8_t cs, uint8_t err, uint8_t spec) noexcept;
86 void OnLssIdInd(co_lss_t*, uint8_t cs, co_unsigned32_t id) noexcept;
87 void OnNidInd(co_lss_t*, uint8_t cs, uint8_t id) noexcept;
88 void OnScanInd(co_lss_t*, uint8_t cs, const co_id* id) noexcept;
89
90 void OnWait(::std::error_code) noexcept;
91
92 void OnRequest(detail::LssRequestBase& req) noexcept;
93 void OnCompletion(detail::LssRequestBase& req) noexcept;
94
95 LssMaster* self{nullptr};
96
97 ev_exec_t* exec{nullptr};
98 Node& node;
99 io::CanControllerBase* ctrl{nullptr};
100 co_nmt_t* nmt{nullptr};
101 co_lss_t* lss{nullptr};
102 uint16_t inhibit{LELY_CO_LSS_INHIBIT};
103 int timeout{LELY_CO_LSS_TIMEOUT};
104
105 co_nmt_lss_req_t* lss_func{nullptr};
106 void* lss_data{nullptr};
107
108 sllist queue;
109
110 int bitrate{0};
111
112 co_id id1{4, 0, 0, 0, 0};
113 co_id id2{4, 0, 0, 0, 0};
114};
115
116namespace detail {
117
118void
119LssSwitchRequestBase::OnRequest(void* data) noexcept {
120 static_cast<LssMaster::Impl_*>(data)->OnSwitch(*this);
121}
122
123void
124LssSwitchSelectiveRequestBase::OnRequest(void* data) noexcept {
125 static_cast<LssMaster::Impl_*>(data)->OnSwitchSelective(*this);
126}
127
128void
129LssSetIdRequestBase::OnRequest(void* data) noexcept {
130 static_cast<LssMaster::Impl_*>(data)->OnSetId(*this);
131}
132
133void
134LssSetBitrateRequestBase::OnRequest(void* data) noexcept {
135 static_cast<LssMaster::Impl_*>(data)->OnSetBitrate(*this);
136}
137
138void
139LssSwitchBitrateRequestBase::OnRequest(void* data) noexcept {
140 static_cast<LssMaster::Impl_*>(data)->OnSwitchBitrate(*this);
141}
142
143void
144LssStoreRequestBase::OnRequest(void* data) noexcept {
145 static_cast<LssMaster::Impl_*>(data)->OnStore(*this);
146}
147
148void
149LssGetVendorIdRequestBase::OnRequest(void* data) noexcept {
150 static_cast<LssMaster::Impl_*>(data)->OnGetVendorId(*this);
151}
152
153void
154LssGetProductCodeRequestBase::OnRequest(void* data) noexcept {
155 static_cast<LssMaster::Impl_*>(data)->OnGetProductCode(*this);
156}
157
158void
159LssGetRevisionRequestBase::OnRequest(void* data) noexcept {
160 static_cast<LssMaster::Impl_*>(data)->OnGetRevision(*this);
161}
162
163void
164LssGetSerialNrRequestBase::OnRequest(void* data) noexcept {
165 static_cast<LssMaster::Impl_*>(data)->OnGetSerialNr(*this);
166}
167
168void
169LssGetIdRequestBase::OnRequest(void* data) noexcept {
170 static_cast<LssMaster::Impl_*>(data)->OnGetId(*this);
171}
172
173void
174LssIdNonConfigRequestBase::OnRequest(void* data) noexcept {
175 static_cast<LssMaster::Impl_*>(data)->OnIdNonConfig(*this);
176}
177
178void
179LssSlowscanRequestBase::OnRequest(void* data) noexcept {
180 static_cast<LssMaster::Impl_*>(data)->OnSlowscan(*this);
181}
182
183void
184LssFastscanRequestBase::OnRequest(void* data) noexcept {
185 static_cast<LssMaster::Impl_*>(data)->OnFastscan(*this);
186}
187
188} // namespace detail
189
191 : impl_(new Impl_(this, exec, node, ctrl, node.nmt())) {}
192
193LssMaster::~LssMaster() = default;
194
196LssMaster::GetExecutor() const noexcept {
197 return impl_->exec;
198}
199
200Node&
201LssMaster::GetNode() const noexcept {
202 return impl_->node;
203}
204
206LssMaster::GetController() const noexcept {
207 return impl_->ctrl;
208}
209
210::std::chrono::microseconds
212 ::std::lock_guard<Impl_> lock(*impl_);
213 ::std::chrono::microseconds::rep value = impl_->inhibit;
214 return ::std::chrono::microseconds(value * 100);
215}
216
217void
218LssMaster::SetInhibit(const ::std::chrono::microseconds& inhibit) {
219 auto value = inhibit.count();
220 if (value >= 0) {
221 if (value > ::std::numeric_limits<uint16_t>::max() * 100)
222 value = ::std::numeric_limits<uint16_t>::max() * 100;
223
224 ::std::lock_guard<Impl_> lock(*impl_);
225 // Round the value up to the nearest multiple of 100 us.
226 impl_->inhibit = (value + 99) / 100;
227 if (impl_->lss) co_lss_set_inhibit(impl_->lss, impl_->inhibit);
228 }
229}
230
231::std::chrono::milliseconds
233 ::std::lock_guard<Impl_> lock(*impl_);
234 return ::std::chrono::milliseconds(impl_->timeout);
235}
236
237void
238LssMaster::SetTimeout(const ::std::chrono::milliseconds& timeout) {
239 auto value = timeout.count();
240 if (value >= 0) {
241 if (value > ::std::numeric_limits<int>::max())
242 value = ::std::numeric_limits<int>::max();
243
244 ::std::lock_guard<Impl_> lock(*impl_);
245 impl_->timeout = value;
246 if (impl_->lss) co_lss_set_timeout(impl_->lss, impl_->timeout);
247 }
248}
249
254 auto req =
255 make_lss_switch_request(exec, state, [p](::std::error_code ec) mutable {
256 p.set(ec ? ::std::make_exception_ptr(
257 ::std::system_error(ec, "AsyncSwitch"))
258 : nullptr);
259 });
260 if (preq) *preq = req;
261 Submit(*req);
262 return p.get_future();
263}
264
270 exec, address, [p](::std::error_code ec) mutable {
271 p.set(ec ? ::std::make_exception_ptr(
272 ::std::system_error(ec, "AsyncSwitchSelective"))
273 : nullptr);
274 });
275 if (preq) *preq = req;
276 Submit(*req);
277 return p.get_future();
278}
279
284 auto req =
285 make_lss_set_id_request(exec, id, [p](::std::error_code ec) mutable {
286 p.set(ec ? ::std::make_exception_ptr(
287 ::std::system_error(ec, "AsyncSetId"))
288 : nullptr);
289 });
290 if (preq) *preq = req;
291 Submit(*req);
292 return p.get_future();
293}
294
300 exec, bitrate, [p](::std::error_code ec) mutable {
301 p.set(ec ? ::std::make_exception_ptr(
302 ::std::system_error(ec, "AsyncSetBitrate"))
303 : nullptr);
304 });
305 if (preq) *preq = req;
306 Submit(*req);
307 return p.get_future();
308}
309
313 auto req = make_lss_store_request(exec, [p](::std::error_code ec) mutable {
314 p.set(ec ? ::std::make_exception_ptr(::std::system_error(ec, "AsyncStore"))
315 : nullptr);
316 });
317 if (preq) *preq = req;
318 Submit(*req);
319 return p.get_future();
320}
321
327 exec, [p](::std::error_code ec, uint32_t number) mutable {
328 if (ec)
329 p.set(util::failure(::std::make_exception_ptr(
330 ::std::system_error(ec, "AsyncGetVendorId"))));
331 else
332 p.set(util::success(number));
333 });
334 if (preq) *preq = req;
335 Submit(*req);
336 return p.get_future();
337}
338
344 exec, [p](::std::error_code ec, uint32_t number) mutable {
345 if (ec)
346 p.set(util::failure(::std::make_exception_ptr(
347 ::std::system_error(ec, "AsyncGetProductCode"))));
348 else
349 p.set(util::success(number));
350 });
351 if (preq) *preq = req;
352 Submit(*req);
353 return p.get_future();
354}
355
361 exec, [p](::std::error_code ec, uint32_t number) mutable {
362 if (ec)
363 p.set(util::failure(::std::make_exception_ptr(
364 ::std::system_error(ec, "AsyncGetRevision"))));
365 else
366 p.set(util::success(number));
367 });
368 if (preq) *preq = req;
369 Submit(*req);
370 return p.get_future();
371}
372
378 exec, [p](::std::error_code ec, uint32_t number) mutable {
379 if (ec)
380 p.set(util::failure(::std::make_exception_ptr(
381 ::std::system_error(ec, "AsyncGetSerialNr"))));
382 else
383 p.set(util::success(number));
384 });
385 if (preq) *preq = req;
386 Submit(*req);
387 return p.get_future();
388}
389
393 auto req = make_lss_get_id_request(
394 exec, [p](::std::error_code ec, uint8_t id) mutable {
395 if (ec)
396 p.set(util::failure(::std::make_exception_ptr(
397 ::std::system_error(ec, "AsyncGetId"))));
398 else
399 p.set(util::success(id));
400 });
401 if (preq) *preq = req;
402 Submit(*req);
403 return p.get_future();
404}
405
411 exec, [p](::std::error_code ec, bool found) mutable {
412 if (ec)
413 p.set(util::failure(::std::make_exception_ptr(
414 ::std::system_error(ec, "AsyncIdNonConfig"))));
415 else
416 p.set(util::success(found));
417 });
418 if (preq) *preq = req;
419 Submit(*req);
420 return p.get_future();
421}
422
425 const LssAddress& hi,
428 auto req = make_lss_slowscan_request(
429 exec, lo, hi,
430 [p](::std::error_code ec, const LssAddress& address) mutable {
431 if (ec)
432 p.set(util::failure(::std::make_exception_ptr(
433 ::std::system_error(ec, "AsyncSlowscan"))));
434 else
435 p.set(util::success(address));
436 });
437 if (preq) *preq = req;
438 Submit(*req);
439 return p.get_future();
440}
441
444 const LssAddress& mask,
447 auto req = make_lss_fastscan_request(
448 exec, address, mask,
449 [p](::std::error_code ec, const LssAddress& address) mutable {
450 if (ec)
451 p.set(util::failure(::std::make_exception_ptr(
452 ::std::system_error(ec, "AsyncFastscan"))));
453 else
454 p.set(util::success(address));
455 });
456 if (preq) *preq = req;
457 Submit(*req);
458 return p.get_future();
459}
460
461void
463 ::std::lock_guard<util::BasicLockable> lock(*this);
464 impl_->Submit(req);
465}
466
467bool
469 auto ec = ::std::make_error_code(::std::errc::operation_canceled);
470 ::std::lock_guard<Impl_> lock(*impl_);
471 return impl_->Cancel(&req, ec) != 0;
472}
473
474::std::size_t
476 auto ec = ::std::make_error_code(::std::errc::operation_canceled);
477 ::std::lock_guard<Impl_> lock(*impl_);
478 return impl_->Cancel(nullptr, ec);
479}
480
481bool
483 ::std::lock_guard<Impl_> lock(*impl_);
484 return impl_->Abort(&req) != 0;
485}
486
487::std::size_t
489 ::std::lock_guard<Impl_> lock(*impl_);
490 return impl_->Abort(nullptr);
491}
492
493void
495 int bitrate, ::std::chrono::milliseconds delay,
496 ::std::function<void(::std::error_code ec)> res) noexcept {
497 if (GetController()) {
498 // Wait for half a delay period to give the CAN channel time to sent the
499 // LSS request.
500 GetNode()
501 .AsyncWait(GetExecutor(), delay / 2)
502 .then(GetExecutor(),
503 [this, delay](LssFuture<void> f) {
504 // Propagate the exception, if any.
505 f.get().value();
506 // Stop transmitting CAN frames.
507 GetController()->stop();
508 // Wait for the second half of the delay period before
509 // switching the bitrate.
510 return GetNode().AsyncWait(GetExecutor(), delay / 2);
511 })
512 .then(GetExecutor(),
513 [this, bitrate, delay](LssFuture<void> f) {
514 // Propagate the exception, if any.
515 f.get().value();
516 // Activate the new bitrate.
517 GetController()->set_bitrate(bitrate);
518 // Wait for the delay period before resuming CAN frame
519 // transmission.
520 return GetNode().AsyncWait(GetExecutor(), delay);
521 })
522 .then(GetExecutor(), [this, res](LssFuture<void> f) noexcept {
523 ::std::error_code ec;
524 try {
525 // Propagate the exception, if any.
526 f.get().value();
527 // Resume CAN frame transmission.
528 GetController()->restart();
529 } catch (::std::system_error& e) {
530 ec = e.code();
531 }
532 // Report the result.
533 res(ec);
534 });
535 } else {
536 // Without a CAN controller, the bit rate switch is a no-op.
537 res({});
538 }
539}
540
541void
543 GetNode().lock();
544}
545
546void
548 GetNode().unlock();
549}
550
551void
553 GetNode().SetTime();
554}
555
556LssMaster::Impl_::Impl_(LssMaster* self_, ev_exec_t* exec_, Node& node_,
557 io::CanControllerBase* ctrl_, co_nmt_t* nmt_)
558 : self(self_),
559 exec(exec_ ? exec_ : static_cast<ev_exec_t*>(node_.GetExecutor())),
560 node(node_),
561 ctrl(ctrl_),
562 nmt(nmt_),
563 lss(co_nmt_get_lss(nmt)) {
564 co_nmt_get_lss_req(nmt, &lss_func, &lss_data);
566 nmt,
567 [](co_nmt_t* nmt, co_lss_t* lss, void* data) noexcept {
568 static_cast<Impl_*>(data)->OnLssReq(nmt, lss);
569 },
570 this);
571
572 if (lss) {
573 inhibit = co_lss_get_inhibit(lss);
574 timeout = co_lss_get_timeout(lss);
575 }
576
577 sllist_init(&queue);
578
579 if (ctrl) {
580 // Try to obtain the current bitrate. It is not an error if this fails.
581 ::std::error_code ec;
582 ctrl->get_bitrate(&bitrate, nullptr, ec);
583 }
584}
585
586LssMaster::Impl_::~Impl_() { co_nmt_set_lss_req(nmt, lss_func, lss_data); }
587
588void
589LssMaster::Impl_::OnLssReq(co_nmt_t*, co_lss_t* lss) noexcept {
590 assert(lss);
591
592 co_lss_set_inhibit(lss, inhibit);
593 co_lss_set_timeout(lss, timeout);
594 this->lss = lss;
595
596 // Post a task to execute the LSS requests.
597 self->GetExecutor().post([this]() noexcept {
598 self->OnStart([this](::std::error_code) noexcept {
599 ::std::lock_guard<Impl_> lock(*this);
600 // Ignore any errors, since we cannot handle them here.
601 co_nmt_lss_con(nmt);
602 });
603 });
604}
605
606void
607LssMaster::Impl_::Submit(detail::LssRequestBase& req) {
608 if (!req.exec) req.exec = self->GetExecutor();
609 auto exec = req.GetExecutor();
610 exec.on_task_init();
611 // Add the request to the queue and start it if it's the first.
612 bool first = sllist_empty(&queue);
613 sllist_push_back(&queue, &req._node);
614 if (first) OnRequest(req);
615}
616
617::std::size_t
618LssMaster::Impl_::Cancel(detail::LssRequestBase* req, ::std::error_code ec) {
619 sllist queue;
620 sllist_init(&queue);
621
622 // Cancel all matching requests, except for the first (ongoing) request.
623 if (Pop(req, queue))
624 // Stop the ongoing request, if any.
625 co_lss_abort_req(lss);
626
627 ::std::size_t n = 0;
628 slnode* node;
629 while ((node = sllist_pop_front(&queue))) {
630 req = static_cast<detail::LssRequestBase*>(ev_task_from_node(node));
631 req->ec = ec;
632
633 auto exec = req->GetExecutor();
634 exec.post(*req);
635 exec.on_task_fini();
636
637 n += n < ::std::numeric_limits<::std::size_t>::max();
638 }
639 return n;
640}
641
642::std::size_t
643LssMaster::Impl_::Abort(detail::LssRequestBase* req) {
644 sllist queue;
645 sllist_init(&queue);
646
647 // Abort all matching requests, except for the first (ongoing) request.
648 Pop(req, queue);
649
650 return ev_task_queue_abort(&queue);
651}
652
653bool
654LssMaster::Impl_::Pop(detail::LssRequestBase* req, sllist& queue) {
655 if (!req) {
656 // Cancel all pending requests, except for the first (ongoing) request.
657 slnode* node = (!lss || co_lss_is_idle(lss))
658 ? nullptr
659 : sllist_pop_front(&this->queue);
660 sllist_append(&queue, &this->queue);
661 if (node) {
662 sllist_push_front(&this->queue, node);
663 req = static_cast<detail::LssRequestBase*>(ev_task_from_node(node));
664 }
665 } else if (&req->_node != sllist_first(&this->queue)) {
666 if (sllist_remove(&queue, &req->_node))
667 sllist_push_back(&this->queue, &req->_node);
668 req = nullptr;
669 }
670 // Return true if the first request matched (but was not removed).
671 return req != nullptr;
672}
673
674void
675LssMaster::Impl_::OnSwitch(detail::LssSwitchRequestBase& req) noexcept {
676 assert(lss);
677 assert(&req._node == sllist_first(&queue));
678
679 int errsv = get_errc();
680 set_errc(0);
681 ::std::error_code ec;
682 if (!co_lss_switch_req(lss, static_cast<int>(req.state)))
683 req.ec.clear();
684 else
685 req.ec = util::make_error_code();
686 set_errc(errsv);
687
688 OnCompletion(req);
689}
690
691void
692LssMaster::Impl_::OnSwitchSelective(
693 detail::LssSwitchSelectiveRequestBase& req) noexcept {
694 assert(lss);
695 assert(&req._node == sllist_first(&queue));
696
697 id1 = {4, req.address.vendor_id, req.address.product_code,
698 req.address.revision, req.address.serial_nr};
699
700 int errsv = get_errc();
701 set_errc(0);
702
703 self->SetTime();
704
706 lss, &id1,
707 [](co_lss_t* lss, uint8_t cs, void* data) noexcept {
708 static_cast<Impl_*>(data)->OnCsInd(lss, cs);
709 },
710 this) == -1) {
711 req.ec = util::make_error_code();
712 OnCompletion(req);
713 }
714
715 set_errc(errsv);
716}
717
718void
719LssMaster::Impl_::OnSetId(detail::LssSetIdRequestBase& req) noexcept {
720 assert(lss);
721 assert(&req._node == sllist_first(&queue));
722
723 int errsv = get_errc();
724 set_errc(0);
725
726 self->SetTime();
727
729 lss, req.id,
730 [](co_lss_t* lss, uint8_t cs, uint8_t err, uint8_t spec,
731 void* data) noexcept {
732 static_cast<Impl_*>(data)->OnErrInd(lss, cs, err, spec);
733 },
734 this) == -1) {
735 req.ec = util::make_error_code();
736 OnCompletion(req);
737 }
738
739 set_errc(errsv);
740}
741
742void
743LssMaster::Impl_::OnSetBitrate(detail::LssSetBitrateRequestBase& req) noexcept {
744 assert(lss);
745 assert(&req._node == sllist_first(&queue));
746
747 int errsv = get_errc();
748 set_errc(0);
749
750 self->SetTime();
751
752 switch (req.bitrate) {
753 case 1000000:
754 case 800000:
755 case 500000:
756 case 250000:
757 case 125000:
758 case 50000:
759 case 20000:
760 case 10000:
762 lss, req.bitrate / 1000,
763 [](co_lss_t* lss, uint8_t cs, uint8_t err, uint8_t spec,
764 void* data) noexcept {
765 static_cast<Impl_*>(data)->OnErrInd(lss, cs, err, spec);
766 },
767 this) == -1) {
768 req.ec = util::make_error_code();
769 OnCompletion(req);
770 }
771 bitrate = req.bitrate;
772 break;
773 default:
774 req.ec = ::std::make_error_code(::std::errc::invalid_argument);
775 OnCompletion(req);
776 break;
777 }
778
779 set_errc(errsv);
780}
781
782void
783LssMaster::Impl_::OnSwitchBitrate(
784 detail::LssSwitchBitrateRequestBase& req) noexcept {
785 assert(lss);
786 assert(&req._node == sllist_first(&queue));
787
788 int errsv = get_errc();
789 set_errc(0);
790
791 self->SetTime();
792
793 if (!bitrate || req.delay < 0 ||
794 req.delay > ::std::numeric_limits<uint16_t>::max()) {
795 req.ec = ::std::make_error_code(::std::errc::invalid_argument);
796 OnCompletion(req);
797 } else if (co_lss_switch_rate_req(lss, req.delay) == -1) {
798 req.ec = util::make_error_code();
799 OnCompletion(req);
800 } else if (!ctrl) {
801 req.ec.clear();
802 OnCompletion(req);
803 } else {
804 ::std::chrono::milliseconds delay(req.delay);
805 // Post a task to perform the actual bit rate switch.
806 self->GetExecutor().post([this, delay]() noexcept {
807 self->OnSwitchBitrate(bitrate, delay, [this](::std::error_code ec) {
808 // Finalize the request.
809 ::std::lock_guard<Impl_> lock(*this);
810 auto task = ev_task_from_node(sllist_first(&queue));
811 assert(task);
812 auto req = static_cast<detail::LssSwitchBitrateRequestBase*>(task);
813 req->ec = ec;
814 OnCompletion(*req);
815 });
816 });
817 }
818
819 set_errc(errsv);
820}
821
822void
823LssMaster::Impl_::OnStore(detail::LssStoreRequestBase& req) noexcept {
824 assert(lss);
825 assert(&req._node == sllist_first(&queue));
826
827 int errsv = get_errc();
828 set_errc(0);
829
830 self->SetTime();
831
833 lss,
834 [](co_lss_t* lss, uint8_t cs, uint8_t err, uint8_t spec,
835 void* data) noexcept {
836 static_cast<Impl_*>(data)->OnErrInd(lss, cs, err, spec);
837 },
838 this) == -1) {
839 req.ec = util::make_error_code();
840 OnCompletion(req);
841 }
842
843 set_errc(errsv);
844}
845
846void
847LssMaster::Impl_::OnGetVendorId(
848 detail::LssGetVendorIdRequestBase& req) noexcept {
849 assert(lss);
850 assert(&req._node == sllist_first(&queue));
851
852 int errsv = get_errc();
853 set_errc(0);
854
855 self->SetTime();
856
857 req.number = 0;
859 lss,
860 [](co_lss_t* lss, uint8_t cs, uint32_t id, void* data) noexcept {
861 static_cast<Impl_*>(data)->OnLssIdInd(lss, cs, id);
862 },
863 this) == -1) {
864 req.ec = util::make_error_code();
865 OnCompletion(req);
866 }
867
868 set_errc(errsv);
869}
870
871void
872LssMaster::Impl_::OnGetProductCode(
873 detail::LssGetProductCodeRequestBase& req) noexcept {
874 assert(lss);
875 assert(&req._node == sllist_first(&queue));
876
877 int errsv = get_errc();
878 set_errc(0);
879
880 self->SetTime();
881
882 req.number = 0;
884 lss,
885 [](co_lss_t* lss, uint8_t cs, uint32_t id, void* data) noexcept {
886 static_cast<Impl_*>(data)->OnLssIdInd(lss, cs, id);
887 },
888 this) == -1) {
889 req.ec = util::make_error_code();
890 OnCompletion(req);
891 }
892
893 set_errc(errsv);
894}
895
896void
897LssMaster::Impl_::OnGetRevision(
898 detail::LssGetRevisionRequestBase& req) noexcept {
899 assert(lss);
900 assert(&req._node == sllist_first(&queue));
901
902 int errsv = get_errc();
903 set_errc(0);
904
905 self->SetTime();
906
907 req.number = 0;
909 lss,
910 [](co_lss_t* lss, uint8_t cs, uint32_t id, void* data) noexcept {
911 static_cast<Impl_*>(data)->OnLssIdInd(lss, cs, id);
912 },
913 this) == -1) {
914 req.ec = util::make_error_code();
915 OnCompletion(req);
916 }
917
918 set_errc(errsv);
919}
920
921void
922LssMaster::Impl_::OnGetSerialNr(
923 detail::LssGetSerialNrRequestBase& req) noexcept {
924 assert(lss);
925 assert(&req._node == sllist_first(&queue));
926
927 int errsv = get_errc();
928 set_errc(0);
929
930 self->SetTime();
931
932 req.number = 0;
934 lss,
935 [](co_lss_t* lss, uint8_t cs, uint32_t id, void* data) noexcept {
936 static_cast<Impl_*>(data)->OnLssIdInd(lss, cs, id);
937 },
938 this) == -1) {
939 req.ec = util::make_error_code();
940 OnCompletion(req);
941 }
942
943 set_errc(errsv);
944}
945
946void
947LssMaster::Impl_::OnGetId(detail::LssGetIdRequestBase& req) noexcept {
948 assert(lss);
949 assert(&req._node == sllist_first(&queue));
950
951 int errsv = get_errc();
952 set_errc(0);
953
954 self->SetTime();
955
956 req.id = 0;
958 lss,
959 [](co_lss_t* lss, uint8_t cs, uint8_t id, void* data) noexcept {
960 static_cast<Impl_*>(data)->OnNidInd(lss, cs, id);
961 },
962 this) == -1) {
963 req.ec = util::make_error_code();
964 OnCompletion(req);
965 }
966
967 set_errc(errsv);
968}
969
970void
971LssMaster::Impl_::OnIdNonConfig(
972 detail::LssIdNonConfigRequestBase& req) noexcept {
973 assert(lss);
974 assert(&req._node == sllist_first(&queue));
975
976 int errsv = get_errc();
977 set_errc(0);
978
979 self->SetTime();
980
982 lss,
983 [](co_lss_t* lss, uint8_t cs, void* data) noexcept {
984 static_cast<Impl_*>(data)->OnCsInd(lss, cs);
985 },
986 this) == -1) {
987 req.ec = util::make_error_code();
988 OnCompletion(req);
989 }
990
991 set_errc(errsv);
992}
993
994void
995LssMaster::Impl_::OnSlowscan(detail::LssSlowscanRequestBase& req) noexcept {
996 assert(lss);
997 assert(&req._node == sllist_first(&queue));
998
999 id1 = {4, req.lo.vendor_id, req.lo.product_code, req.lo.revision,
1000 req.lo.serial_nr};
1001 id2 = {4, req.hi.vendor_id, req.hi.product_code, req.hi.revision,
1002 req.hi.serial_nr};
1003
1004 int errsv = get_errc();
1005 set_errc(0);
1006
1007 self->SetTime();
1008
1009 req.address = {0, 0, 0, 0};
1011 lss, &id1, &id2,
1012 [](co_lss_t* lss, uint8_t cs, const co_id* id, void* data) noexcept {
1013 static_cast<Impl_*>(data)->OnScanInd(lss, cs, id);
1014 },
1015 this) == -1) {
1016 req.ec = util::make_error_code();
1017 OnCompletion(req);
1018 }
1019
1020 set_errc(errsv);
1021}
1022
1023void
1024LssMaster::Impl_::OnFastscan(detail::LssFastscanRequestBase& req) noexcept {
1025 assert(lss);
1026 assert(&req._node == sllist_first(&queue));
1027
1028 id1 = {4, req.address.vendor_id, req.address.product_code,
1029 req.address.revision, req.address.serial_nr};
1030 id2 = {4, req.mask.vendor_id, req.mask.product_code, req.mask.revision,
1031 req.mask.serial_nr};
1032
1033 int errsv = get_errc();
1034 set_errc(0);
1035
1036 self->SetTime();
1037
1039 lss, &id1, &id2,
1040 [](co_lss_t* lss, uint8_t cs, const co_id* id, void* data) noexcept {
1041 static_cast<Impl_*>(data)->OnScanInd(lss, cs, id);
1042 },
1043 this) == -1) {
1044 req.ec = util::make_error_code();
1045 OnCompletion(req);
1046 }
1047
1048 set_errc(errsv);
1049}
1050
1051void
1052LssMaster::Impl_::OnCsInd(co_lss_t*, uint8_t cs) noexcept {
1053 auto task = ev_task_from_node(sllist_first(&queue));
1054 assert(task);
1055 auto req = static_cast<detail::LssSwitchRequestBase*>(task);
1056
1057 if (cs)
1058 req->ec.clear();
1059 else
1060 req->ec = ::std::make_error_code(::std::errc::timed_out);
1061
1062 OnCompletion(*req);
1063}
1064
1065void
1066LssMaster::Impl_::OnErrInd(co_lss_t*, uint8_t cs, uint8_t err,
1067 uint8_t) noexcept {
1068 auto task = ev_task_from_node(sllist_first(&queue));
1069 assert(task);
1070 auto req = static_cast<detail::LssRequestBase*>(task);
1071
1072 req->ec = ::std::make_error_code(::std::errc::protocol_error);
1073 switch (cs) {
1074 case 0:
1075 req->ec = ::std::make_error_code(::std::errc::timed_out);
1076 break;
1077 case 0x11: // 'configure node-ID'
1078 switch (err) {
1079 case 0: // Protocol successfully completed
1080 req->ec.clear();
1081 break;
1082 case 1: // NID out of range
1083 req->ec = ::std::make_error_code(::std::errc::result_out_of_range);
1084 break;
1085 }
1086 break;
1087 case 0x13: // 'configure bit timing parameters'
1088 switch (err) {
1089 case 0: // Protocol successfully completed
1090 req->ec.clear();
1091 break;
1092 case 1: // Bit timing / Bit rate not supported
1093 req->ec = ::std::make_error_code(::std::errc::invalid_argument);
1094 break;
1095 }
1096 break;
1097 case 0x17: // 'store configuration'
1098 switch (err) {
1099 case 0: // Protocol successfully completed
1100 req->ec.clear();
1101 break;
1102 case 1: // Store configuration not supported
1103 req->ec =
1104 ::std::make_error_code(::std::errc::operation_not_supported);
1105 break;
1106 case 2: // Storage media access error
1107 req->ec = ::std::make_error_code(::std::errc::io_error);
1108 break;
1109 }
1110 break;
1111 }
1112
1113 OnCompletion(*req);
1114}
1115
1116void
1117LssMaster::Impl_::OnLssIdInd(co_lss_t*, uint8_t cs,
1118 co_unsigned32_t id) noexcept {
1119 auto task = ev_task_from_node(sllist_first(&queue));
1120 assert(task);
1121 auto req = static_cast<detail::LssGetNumberRequestBase*>(task);
1122
1123 if (cs) {
1124 req->ec.clear();
1125 req->number = id;
1126 } else {
1127 req->ec = ::std::make_error_code(::std::errc::timed_out);
1128 }
1129
1130 OnCompletion(*req);
1131}
1132
1133void
1134LssMaster::Impl_::OnNidInd(co_lss_t*, uint8_t cs, uint8_t id) noexcept {
1135 auto task = ev_task_from_node(sllist_first(&queue));
1136 assert(task);
1137 auto req = static_cast<detail::LssGetIdRequestBase*>(task);
1138
1139 if (cs) {
1140 req->ec.clear();
1141 req->id = id;
1142 } else {
1143 req->ec = ::std::make_error_code(::std::errc::timed_out);
1144 }
1145
1146 OnCompletion(*req);
1147}
1148
1149void
1150LssMaster::Impl_::OnScanInd(co_lss_t*, uint8_t cs, const co_id* id) noexcept {
1151 assert(!cs || id);
1152 auto task = ev_task_from_node(sllist_first(&queue));
1153 assert(task);
1154 auto req = static_cast<detail::LssScanRequestBase*>(task);
1155
1156 if (cs) {
1157 req->ec.clear();
1158 req->address.vendor_id = id->vendor_id;
1159 req->address.product_code = id->product_code;
1160 req->address.revision = id->revision;
1161 req->address.serial_nr = id->serial_nr;
1162 } else {
1163 req->ec = ::std::make_error_code(::std::errc::timed_out);
1164 }
1165
1166 OnCompletion(*req);
1167}
1168
1169void
1170LssMaster::Impl_::OnRequest(detail::LssRequestBase& req) noexcept {
1171 if (lss) {
1172 req.OnRequest(this);
1173 } else {
1174 req.ec = ::std::make_error_code(::std::errc::operation_not_permitted);
1175 OnCompletion(req);
1176 }
1177}
1178
1179void
1180LssMaster::Impl_::OnCompletion(detail::LssRequestBase& req) noexcept {
1181 assert(&req._node == sllist_first(&queue));
1182 sllist_pop_front(&queue);
1183
1184 auto exec = req.GetExecutor();
1185 exec.post(req);
1186 exec.on_task_fini();
1187
1188 auto task = ev_task_from_node(sllist_first(&queue));
1189 if (task) OnRequest(*static_cast<detail::LssRequestBase*>(task));
1190}
1191
1192} // namespace canopen
1193
1194} // namespace lely
1195
1196#endif // !LELY_NO_CO_LSS
The base class for CANopen LSS masters.
bool Abort(detail::LssRequestBase &req)
Aborts a pending LSS request.
Definition: lss_master.cpp:482
ev::Executor GetExecutor() const noexcept
Returns the default executor used to execute completion tasks of LSS requests.
Definition: lss_master.cpp:196
LssMaster(ev_exec_t *exec, Node &node, io::CanControllerBase *ctrl=nullptr)
Creates a new CANopen LSS master.
Definition: lss_master.cpp:190
LssFuture< uint8_t > AsyncGetId(ev_exec_t *exec, detail::LssGetIdRequestBase **preq=nullptr)
Queues an asynchronous LSS 'inquire node-ID' request and creates a future which becomes ready once th...
Definition: lss_master.cpp:391
LssFuture< LssAddress > AsyncSlowscan(ev_exec_t *exec, const LssAddress &lo, const LssAddress &hi, detail::LssSlowscanRequestBase **preq=nullptr)
Queues an asynchronous 'LSS Slowscan' request and creates a future which becomes ready once the reque...
Definition: lss_master.cpp:424
LssFuture< void > AsyncSetBitrate(ev_exec_t *exec, int bitrate, detail::LssSetBitrateRequestBase **preq=nullptr)
Queues an asynchronous LSS 'configure bit timing parameters' request and creates a future which becom...
Definition: lss_master.cpp:296
LssFuture< uint32_t > AsyncGetProductCode(ev_exec_t *exec, detail::LssGetProductCodeRequestBase **preq=nullptr)
Queues an asynchronous LSS 'inquire identity product-code' request and creates a future which becomes...
Definition: lss_master.cpp:340
Node & GetNode() const noexcept
Returns the CANopen master node.
Definition: lss_master.cpp:201
void SetTime()
Update the CAN network time.
Definition: lss_master.cpp:552
LssFuture< void > AsyncSwitchSelective(ev_exec_t *exec, const LssAddress &address, detail::LssSwitchSelectiveRequestBase **preq=nullptr)
Queues an asynchronous LSS 'switch state selective' request and creates a future which becomes ready ...
Definition: lss_master.cpp:266
LssFuture< LssAddress > AsyncFastscan(ev_exec_t *exec, const LssAddress &address={0, 0, 0, 0}, const LssAddress &mask={0, 0, 0, 0}, detail::LssFastscanRequestBase **preq=nullptr)
Queues an asynchronous 'LSS Fastscan' request and creates a future which becomes ready once the reque...
Definition: lss_master.cpp:443
LssFuture< void > AsyncSwitch(ev_exec_t *exec, LssState state=LssState::WAITING, detail::LssSwitchRequestBase **preq=nullptr)
Queues an asynchronous LSS 'switch state global' request and creates a future which becomes ready onc...
Definition: lss_master.cpp:251
LssFuture< uint32_t > AsyncGetVendorId(ev_exec_t *exec, detail::LssGetVendorIdRequestBase **preq=nullptr)
Queues an asynchronous LSS 'inquire identity vendor-ID' request and creates a future which becomes re...
Definition: lss_master.cpp:323
bool Cancel(detail::LssRequestBase &req)
Cancels a pending LSS request.
Definition: lss_master.cpp:468
::std::size_t AbortAll()
Aborts all pending LSS requests.
Definition: lss_master.cpp:488
void Submit(detail::LssRequestBase &req)
Queues an LSS request.
Definition: lss_master.cpp:462
LssFuture< uint32_t > AsyncGetSerialNr(ev_exec_t *exec, detail::LssGetSerialNrRequestBase **preq=nullptr)
Queues an asynchronous LSS 'inquire identity serial-number' request and creates a future which become...
Definition: lss_master.cpp:374
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: lss_master.cpp:542
void SetTimeout(const ::std::chrono::milliseconds &timeout)
Sets the timeout when waiting for a slave to respond to an LSS request.
Definition: lss_master.cpp:238
::std::chrono::microseconds GetInhibit() const
Returns the inhibit time between successive CAN frames.
Definition: lss_master.cpp:211
virtual void OnSwitchBitrate(int bitrate, ::std::chrono::milliseconds delay, ::std::function< void(::std::error_code ec)> res) noexcept
The function invoked when the master activates the bit rate of all CANopen devices in the network.
Definition: lss_master.cpp:494
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
Definition: lss_master.cpp:547
void SetInhibit(const ::std::chrono::microseconds &inhibit)
Sets the inhibit time between successive CAN frames.
Definition: lss_master.cpp:218
::std::chrono::milliseconds GetTimeout() const
Returns the timeout when waiting for a slave to respond to an LSS request.
Definition: lss_master.cpp:232
io::CanControllerBase * GetController() const noexcept
Returns the pointer to the CAN controller for this node passed to the constructor (may be a null poin...
Definition: lss_master.cpp:206
LssFuture< uint32_t > AsyncGetRevision(ev_exec_t *exec, detail::LssGetRevisionRequestBase **preq=nullptr)
Queues an asynchronous LSS 'inquire identity revision-number' request and creates a future which beco...
Definition: lss_master.cpp:357
LssFuture< bool > AsyncIdNonConfig(ev_exec_t *exec, detail::LssIdNonConfigRequestBase **preq=nullptr)
Queues an asynchronous LSS 'identify non-configured remote slave' request and creates a future which ...
Definition: lss_master.cpp:407
LssFuture< void > AsyncSetId(ev_exec_t *exec, uint8_t id, detail::LssSetIdRequestBase **preq=nullptr)
Queues an asynchronous LSS 'configure node-ID' request and creates a future which becomes ready once ...
Definition: lss_master.cpp:281
::std::size_t CancelAll()
Cancels all pending LSS requests and stops the ongoing request, if any.
Definition: lss_master.cpp:475
LssFuture< void > AsyncStore(ev_exec_t *exec, detail::LssStoreRequestBase **preq=nullptr)
Queues an asynchronous LSS 'store configuration' request and creates a future which becomes ready onc...
Definition: lss_master.cpp:311
The base class for CANopen nodes.
Definition: node.hpp:116
void SetTime()
Updates the CAN network time.
Definition: node.cpp:415
An abstract task executor. This class is a wrapper around #ev_exec_t*.
Definition: exec.hpp:38
A future.
Definition: future.hpp:384
A promise.
Definition: future.hpp:60
Future< T, E > get_future() const noexcept
Returns a lely::ev::Future with (a reference to) the same shared state as *this.
Definition: future.hpp:188
bool set(U &&u)
Satisfies a promise, if it was not aready satisfied, and stores the specified value as the result in ...
Definition: future.hpp:166
A reference to an abstract CAN controller.
Definition: can.hpp:286
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
Definition: can_net.hpp:109
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: can_net.hpp:104
An abstract interface conforming to the BasicLockable concept.
Definition: mutex.hpp:34
This is the internal header file of the C++ CANopen application library.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:932
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
This header file is part of the CANopen library; it contains the Layer Setting Services (LSS) and pro...
int co_lss_get_vendor_id_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the 'inquire identity vendor-ID' service.
Definition: lss.c:1142
int co_lss_set_id_req(co_lss_t *lss, co_unsigned8_t id, co_lss_err_ind_t *ind, void *data)
Requests the 'configure node-ID' service.
Definition: lss.c:1021
void co_lss_set_timeout(co_lss_t *lss, int timeout)
Sets the timeout of an LSS master service.
Definition: lss.c:932
co_unsigned16_t co_lss_get_inhibit(const co_lss_t *lss)
Returns the inhibit time (in multiples of 100 microseconds) of an LSS master service.
Definition: lss.c:908
int co_lss_slowscan_req(co_lss_t *lss, const struct co_id *lo, const struct co_id *hi, co_lss_scan_ind_t *ind, void *data)
Requests the 'LSS Slowscan' service.
Definition: lss.c:1329
int co_lss_switch_rate_req(co_lss_t *lss, int delay)
Requests the 'activate bit timing parameters' service.
Definition: lss.c:1094
int co_lss_get_id_req(co_lss_t *lss, co_lss_nid_ind_t *ind, void *data)
Requests the 'inquire node-ID' service.
Definition: lss.c:1244
int co_lss_get_revision_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the 'inquire identity revision-number' service.
Definition: lss.c:1192
int co_lss_switch_sel_req(co_lss_t *lss, const struct co_id *id, co_lss_cs_ind_t *ind, void *data)
Requests the 'switch state selective' service.
Definition: lss.c:999
int co_lss_switch_req(co_lss_t *lss, co_unsigned8_t mode)
Requests the 'switch state global' service.
Definition: lss.c:977
int co_lss_set_rate_req(co_lss_t *lss, co_unsigned16_t rate, co_lss_err_ind_t *ind, void *data)
Requests the 'configure bit timing parameters' service.
Definition: lss.c:1053
int co_lss_is_idle(const co_lss_t *lss)
Returns 1 if the specified LSS master is idle, and 0 if a request is ongoing.
Definition: lss.c:961
int co_lss_get_timeout(const co_lss_t *lss)
Returns the timeout (in milliseconds) of an LSS master service.
Definition: lss.c:924
#define LELY_CO_LSS_INHIBIT
The default LSS inhibit time (in multiples of 100 microseconds).
Definition: lss.h:30
int co_lss_get_product_code_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the 'inquire identity product-code' service.
Definition: lss.c:1167
int co_lss_store_req(co_lss_t *lss, co_lss_err_ind_t *ind, void *data)
Requests the 'store configuration' service.
Definition: lss.c:1117
int co_lss_id_non_cfg_slave_req(co_lss_t *lss, co_lss_cs_ind_t *ind, void *data)
Requests the 'LSS identify non-configured remote slave' service.
Definition: lss.c:1303
#define LELY_CO_LSS_TIMEOUT
The default LSS timeout (in milliseconds).
Definition: lss.h:35
int co_lss_fastscan_req(co_lss_t *lss, const struct co_id *id, const struct co_id *mask, co_lss_scan_ind_t *ind, void *data)
Requests the 'LSS Fastscan' service.
Definition: lss.c:1365
int co_lss_get_serial_nr_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the 'inquire identity serial-number' service.
Definition: lss.c:1218
void co_lss_abort_req(co_lss_t *lss)
Aborts the current LSS master request.
Definition: lss.c:969
void co_lss_set_inhibit(co_lss_t *lss, co_unsigned16_t inhibit)
Sets the inhibit time between successive LSS messages of an LSS master service.
Definition: lss.c:916
This header file is part of the C++ CANopen application library; it contains the CANopen Layer Settin...
typename::std::enable_if< compat::is_invocable< F,::std::error_code, uint32_t >::value, detail::LssGetSerialNrRequestWrapper< F > * >::type make_lss_get_serial_nr_request(ev_exec_t *exec, F &&con)
Creates an LSS 'inquire identity serial-number' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code, LssAddress >::value, detail::LssFastscanRequestWrapper< F > * >::type make_lss_fastscan_request(ev_exec_t *exec, const LssAddress &address, const LssAddress &mask, F &&con)
Creates an 'LSS Fastscan' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code, uint32_t >::value, detail::LssGetProductCodeRequestWrapper< F > * >::type make_lss_get_product_code_request(ev_exec_t *exec, F &&con)
Creates an LSS 'inquire identity product-code' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code >::value, detail::LssSetBitrateRequestWrapper< F > * >::type make_lss_set_bitrate_request(ev_exec_t *exec, int bitrate, F &&con)
Creates an LSS 'configure bit timing parameters' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code >::value, detail::LssSwitchRequestWrapper< F > * >::type make_lss_switch_request(ev_exec_t *exec, LssState state, F &&con)
Creates an LSS 'switch state global' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code, bool >::value, detail::LssIdNonConfigRequestWrapper< F > * >::type make_lss_id_non_config_request(ev_exec_t *exec, F &&con)
Creates an LSS 'identify non-configured remote slave' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code, uint32_t >::value, detail::LssGetVendorIdRequestWrapper< F > * >::type make_lss_get_vendor_id_request(ev_exec_t *exec, F &&con)
Creates an LSS 'inquire identity vendor-ID' request with a completion task.
LssState
The states of the LSS finite state automaton (FSA) of a slave device.
Definition: lss_master.hpp:80
typename::std::enable_if< compat::is_invocable< F,::std::error_code >::value, detail::LssSwitchSelectiveRequestWrapper< F > * >::type make_lss_switch_selective_request(ev_exec_t *exec, const LssAddress &address, F &&con)
Creates an LSS 'switch state selective' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code, LssAddress >::value, detail::LssSlowscanRequestWrapper< F > * >::type make_lss_slowscan_request(ev_exec_t *exec, const LssAddress &lo, const LssAddress &hi, F &&con)
Creates an 'LSS Slowscan' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code >::value, detail::LssSetIdRequestWrapper< F > * >::type make_lss_set_id_request(ev_exec_t *exec, uint8_t id, F &&con)
Creates an LSS 'configure node-ID' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code, uint8_t >::value, detail::LssGetIdRequestWrapper< F > * >::type make_lss_get_id_request(ev_exec_t *exec, F &&con)
Creates an LSS 'inquire node-ID' request with a completion task.
typename::std::enable_if< compat::is_invocable< F,::std::error_code >::value, detail::LssStoreRequestWrapper< F > * >::type make_lss_store_request(ev_exec_t *exec, F &&con)
Creates an LSS 'store configuration' request with a completion task.
::std::error_code make_error_code(SdoErrc e) noexcept
Creates an error code corresponding to an SDO abort code.
Definition: sdo_error.cpp:170
typename::std::enable_if< compat::is_invocable< F,::std::error_code, uint32_t >::value, detail::LssGetRevisionRequestWrapper< F > * >::type make_lss_get_revision_request(ev_exec_t *exec, F &&con)
Creates an LSS 'inquire identity revision-number' request with a completion task.
This header file is part of the CANopen library; it contains the network management (NMT) declaration...
void co_nmt_lss_req_t(co_nmt_t *nmt, co_lss_t *lss, void *data)
The type of a CANopen LSS request function, invoked by an NMT master before booting the slaves (see F...
Definition: nmt.h:188
void co_nmt_get_lss_req(const co_nmt_t *nmt, co_nmt_lss_req_t **pind, void **pdata)
Retrieves the request function invoked to perform LSS when booting an NMT master.
Definition: nmt.c:1478
void co_nmt_set_lss_req(co_nmt_t *nmt, co_nmt_lss_req_t *ind, void *data)
Sets the request function invoked to perform LSS when booting an NMT master.
Definition: nmt.c:1489
co_lss_t * co_nmt_get_lss(const co_nmt_t *nmt)
Returns a pointer to the LSS master/slave service.
Definition: nmt.c:2282
int co_nmt_lss_con(co_nmt_t *nmt)
Confirms the completion of the process when booting an NMT master.
Definition: nmt.c:1853
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
Definition: sllist.h:194
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
Definition: sllist.h:257
void sllist_push_front(struct sllist *list, struct slnode *node)
Pushes a node to the front of a singly-linked list.
Definition: sllist.h:221
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
Definition: sllist.c:46
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
Definition: sllist.h:232
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
Definition: sllist.h:202
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
Definition: sllist.h:243
struct slnode * sllist_first(const struct sllist *list)
Returns a pointer to the first node in a singly-linked list.
Definition: sllist.h:271
A CANopen LSS master/slave service.
Definition: lss.c:44
A CANopen NMT master/slave service.
Definition: nmt.c:148
An identity record.
Definition: dev.h:33
The 128-bit number uniquely identifying each CANopen node.
Definition: lss_master.hpp:61
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: lss_master.cpp:48
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
Definition: lss_master.cpp:53
A singly-linked list.
Definition: sllist.h:52
A node in a singly-linked list.
Definition: sllist.h:40
size_t ev_task_queue_abort(struct sllist *queue)
Aborts the tasks in queue by invoking ev_exec_on_task_fini() for each of them.
Definition: task.c:55
struct ev_task * ev_task_from_node(struct slnode *node)
Converts a pointer to a node in a queue to the address of the task containing the node.
Definition: task.c:32