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