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
49 self->lock();
50 }
51
52 void
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
197 return impl_->exec;
198}
199
200Node&
202 return impl_->node;
203}
204
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
550
551void
555
556LssMaster::Impl_::Impl_(LssMaster* self_, ev_exec_t* exec_, Node& node_,
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
A CANopen value.
Definition val.hpp:42
The base class for CANopen LSS masters.
bool Abort(detail::LssRequestBase &req)
Aborts a pending LSS request.
ev::Executor GetExecutor() const noexcept
Returns the default executor used to execute completion tasks of LSS requests.
LssMaster(ev_exec_t *exec, Node &node, io::CanControllerBase *ctrl=nullptr)
Creates a new CANopen LSS master.
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...
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...
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...
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...
Node & GetNode() const noexcept
Returns the CANopen master node.
void SetTime()
Update the CAN network time.
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 ...
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...
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...
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...
bool Cancel(detail::LssRequestBase &req)
Cancels a pending LSS request.
::std::size_t AbortAll()
Aborts all pending LSS requests.
void Submit(detail::LssRequestBase &req)
Queues an LSS request.
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...
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process,...
void SetTimeout(const ::std::chrono::milliseconds &timeout)
Sets the timeout when waiting for a slave to respond to an LSS request.
::std::chrono::microseconds GetInhibit() const
Returns the inhibit time between successive CAN frames.
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.
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
void SetInhibit(const ::std::chrono::microseconds &inhibit)
Sets the inhibit time between successive CAN frames.
::std::chrono::milliseconds GetTimeout() const
Returns the timeout when waiting for a slave to respond to an LSS request.
io::CanControllerBase * GetController() const noexcept
Returns the pointer to the CAN controller for this node passed to the constructor (may be a null poin...
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...
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 ...
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 ...
::std::size_t CancelAll()
Cancels all pending LSS requests and stops the ongoing request, if any.
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...
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 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.
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.
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.
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process,...
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
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