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 
38 namespace lely {
39 
40 namespace canopen {
41 
43  Impl_(LssMaster* self, ev_exec_t* exec, Node& node,
44  io::CanControllerBase* ctrl, co_nmt_t* nmt);
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 
116 namespace detail {
117 
118 void
119 LssSwitchRequestBase::OnRequest(void* data) noexcept {
120  static_cast<LssMaster::Impl_*>(data)->OnSwitch(*this);
121 }
122 
123 void
124 LssSwitchSelectiveRequestBase::OnRequest(void* data) noexcept {
125  static_cast<LssMaster::Impl_*>(data)->OnSwitchSelective(*this);
126 }
127 
128 void
129 LssSetIdRequestBase::OnRequest(void* data) noexcept {
130  static_cast<LssMaster::Impl_*>(data)->OnSetId(*this);
131 }
132 
133 void
134 LssSetBitrateRequestBase::OnRequest(void* data) noexcept {
135  static_cast<LssMaster::Impl_*>(data)->OnSetBitrate(*this);
136 }
137 
138 void
139 LssSwitchBitrateRequestBase::OnRequest(void* data) noexcept {
140  static_cast<LssMaster::Impl_*>(data)->OnSwitchBitrate(*this);
141 }
142 
143 void
144 LssStoreRequestBase::OnRequest(void* data) noexcept {
145  static_cast<LssMaster::Impl_*>(data)->OnStore(*this);
146 }
147 
148 void
149 LssGetVendorIdRequestBase::OnRequest(void* data) noexcept {
150  static_cast<LssMaster::Impl_*>(data)->OnGetVendorId(*this);
151 }
152 
153 void
154 LssGetProductCodeRequestBase::OnRequest(void* data) noexcept {
155  static_cast<LssMaster::Impl_*>(data)->OnGetProductCode(*this);
156 }
157 
158 void
159 LssGetRevisionRequestBase::OnRequest(void* data) noexcept {
160  static_cast<LssMaster::Impl_*>(data)->OnGetRevision(*this);
161 }
162 
163 void
164 LssGetSerialNrRequestBase::OnRequest(void* data) noexcept {
165  static_cast<LssMaster::Impl_*>(data)->OnGetSerialNr(*this);
166 }
167 
168 void
169 LssGetIdRequestBase::OnRequest(void* data) noexcept {
170  static_cast<LssMaster::Impl_*>(data)->OnGetId(*this);
171 }
172 
173 void
174 LssIdNonConfigRequestBase::OnRequest(void* data) noexcept {
175  static_cast<LssMaster::Impl_*>(data)->OnIdNonConfig(*this);
176 }
177 
178 void
179 LssSlowscanRequestBase::OnRequest(void* data) noexcept {
180  static_cast<LssMaster::Impl_*>(data)->OnSlowscan(*this);
181 }
182 
183 void
184 LssFastscanRequestBase::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 
193 LssMaster::~LssMaster() = default;
194 
196 LssMaster::GetExecutor() const noexcept {
197  return impl_->exec;
198 }
199 
200 Node&
201 LssMaster::GetNode() const noexcept {
202  return impl_->node;
203 }
204 
206 LssMaster::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 
217 void
218 LssMaster::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 
237 void
238 LssMaster::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 
299  auto req = make_lss_set_bitrate_request(
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 
461 void
463  ::std::lock_guard<util::BasicLockable> lock(*this);
464  impl_->Submit(req);
465 }
466 
467 bool
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 
481 bool
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 
493 void
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 
541 void
543  GetNode().lock();
544 }
545 
546 void
548  GetNode().unlock();
549 }
550 
551 void
553  GetNode().SetTime();
554 }
555 
556 LssMaster::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 
586 LssMaster::Impl_::~Impl_() { co_nmt_set_lss_req(nmt, lss_func, lss_data); }
587 
588 void
589 LssMaster::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 
606 void
607 LssMaster::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
618 LssMaster::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
643 LssMaster::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 
653 bool
654 LssMaster::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 
674 void
675 LssMaster::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 
691 void
692 LssMaster::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 
718 void
719 LssMaster::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 
728  if (co_lss_set_id_req(
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 
742 void
743 LssMaster::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 
782 void
783 LssMaster::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 
822 void
823 LssMaster::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 
832  if (co_lss_store_req(
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 
846 void
847 LssMaster::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 
871 void
872 LssMaster::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 
896 void
897 LssMaster::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 
921 void
922 LssMaster::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 
946 void
947 LssMaster::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;
957  if (co_lss_get_id_req(
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 
970 void
971 LssMaster::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 
994 void
995 LssMaster::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};
1010  if (co_lss_slowscan_req(
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 
1023 void
1024 LssMaster::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 
1038  if (co_lss_fastscan_req(
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 
1051 void
1052 LssMaster::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 
1065 void
1066 LssMaster::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 
1116 void
1117 LssMaster::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 
1133 void
1134 LssMaster::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 
1149 void
1150 LssMaster::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 
1169 void
1170 LssMaster::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 
1179 void
1180 LssMaster::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 >::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, 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.
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, 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::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.
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::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::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.
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::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.
::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 >::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, 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, 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.
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