Lely core libraries  2.2.5
node.cpp
Go to the documentation of this file.
1 
24 #include "coapp.hpp"
25 #include <lely/coapp/node.hpp>
26 
27 #include <string>
28 
29 #include <cassert>
30 
31 #include <lely/co/dev.hpp>
32 #include <lely/co/emcy.hpp>
33 #include <lely/co/lss.hpp>
34 #include <lely/co/nmt.hpp>
35 #include <lely/co/rpdo.hpp>
36 #include <lely/co/sync.hpp>
37 #include <lely/co/time.hpp>
38 #include <lely/co/tpdo.hpp>
39 
40 namespace lely {
41 
42 namespace canopen {
43 
45 struct Node::Impl_ {
46  Impl_(Node* self, CANNet* net, CODev* dev);
47 
48  void OnCsInd(CONMT* nmt, uint8_t cs) noexcept;
49  void OnHbInd(CONMT* nmt, uint8_t id, int state, int reason) noexcept;
50  void OnStInd(CONMT* nmt, uint8_t id, uint8_t st) noexcept;
51 
52  void OnRpdoInd(CORPDO* pdo, uint32_t ac, const void* ptr, size_t n) noexcept;
53  void OnRpdoErr(CORPDO* pdo, uint16_t eec, uint8_t er) noexcept;
54 
55  void OnTpdoInd(COTPDO* pdo, uint32_t ac, const void* ptr, size_t n) noexcept;
56 
57  void OnSyncInd(CONMT* nmt, uint8_t cnt) noexcept;
58  void OnSyncErr(COSync* sync, uint16_t eec, uint8_t er) noexcept;
59 
60  void OnTimeInd(COTime* time, const timespec* tp) noexcept;
61 
62  void OnEmcyInd(COEmcy* emcy, uint8_t id, uint16_t ec, uint8_t er,
63  uint8_t msef[5]) noexcept;
64 
65  void OnRateInd(COLSS*, uint16_t rate, int delay) noexcept;
66  int OnStoreInd(COLSS*, uint8_t id, uint16_t rate) noexcept;
67 
68  void RpdoRtr(int num) noexcept;
69 
70  Node* self{nullptr};
71 
72  ::std::function<void(io::CanState, io::CanState)> on_can_state;
73  ::std::function<void(io::CanError)> on_can_error;
74 
76 
77  ::std::function<void(NmtCommand)> on_command;
78  ::std::function<void(uint8_t, bool)> on_heartbeat;
79  ::std::function<void(uint8_t, NmtState)> on_state;
80  ::std::function<void(int, ::std::error_code, const void*, ::std::size_t)>
81  on_rpdo;
82  ::std::function<void(int, uint16_t, uint8_t)> on_rpdo_error;
83  ::std::function<void(int, ::std::error_code, const void*, ::std::size_t)>
84  on_tpdo;
85  ::std::function<void(uint8_t, const time_point&)> on_sync;
86  ::std::function<void(uint16_t, uint8_t)> on_sync_error;
87  ::std::function<void(const ::std::chrono::system_clock::time_point&)> on_time;
88  ::std::function<void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy;
89  ::std::function<void(int, ::std::chrono::milliseconds)> on_switch_bitrate;
90 };
91 
93  const ::std::string& dcf_txt, const ::std::string& dcf_bin,
94  uint8_t id)
95  : io::CanNet(exec, timer, chan, 0, 0),
96  Device(dcf_txt, dcf_bin, id, this),
97  tpdo_event_mutex(*this),
98  impl_(new Impl_(this, net(), Device::dev())) {
99  // Start processing CAN frames.
100  start();
101 }
102 
103 Node::~Node() = default;
104 
106 Node::GetExecutor() const noexcept {
107  return get_executor();
108 }
109 
111 Node::GetContext() const noexcept {
112  return get_ctx();
113 }
114 
115 io::Clock
116 Node::GetClock() const noexcept {
117  return get_clock();
118 }
119 
120 void
121 Node::SubmitWait(const time_point& t, io_tqueue_wait& wait) {
122  wait.value = util::to_timespec(t);
123  io_tqueue_submit_wait(*this, &wait);
124 }
125 
126 void
127 Node::SubmitWait(const duration& d, io_tqueue_wait& wait) {
128  SubmitWait(GetClock().gettime() + d, wait);
129 }
130 
132 Node::AsyncWait(ev_exec_t* exec, const time_point& t, io_tqueue_wait** pwait) {
133  if (!exec) exec = GetExecutor();
134  auto value = util::to_timespec(t);
135  ev::Future<void, int> f{io_tqueue_async_wait(*this, exec, &value, pwait)};
136  if (!f) util::throw_errc("AsyncWait");
137  return f.then(exec, [](ev::Future<void, int> f) {
138  // Convert the error code into an exception pointer.
139  int errc = f.get().error();
140  if (errc) util::throw_errc("AsyncWait", errc);
141  });
142 }
143 
145 Node::AsyncWait(ev_exec_t* exec, const duration& d, io_tqueue_wait** pwait) {
146  return AsyncWait(exec, GetClock().gettime() + d, pwait);
147 }
148 
149 bool
151  return io_tqueue_cancel_wait(*this, &wait) != 0;
152 }
153 
154 bool
156  return io_tqueue_abort_wait(*this, &wait) != 0;
157 }
158 
161  ::std::chrono::milliseconds delay) {
162  // Stop transmitting CAN frames.
163  ctrl.stop();
164  return AsyncWait(GetExecutor(), delay)
165  .then(GetExecutor(),
166  [this, delay](ev::Future<void, ::std::exception_ptr> f) {
167  // Propagate the exception, if any.
168  f.get().value();
169  // Wait for the delay period before switching the bitrate.
170  return AsyncWait(GetExecutor(), delay);
171  })
172  .then(GetExecutor(),
173  [this, &ctrl, bitrate,
175  // Propagate the exception, if any.
176  f.get().value();
177  // Activate the new bitrate.
178  ctrl.set_bitrate(bitrate);
179  // Wait for the delay period before resuming CAN frame
180  // transmission.
181  return AsyncWait(GetExecutor(), delay);
182  })
183  .then(GetExecutor(),
184  [this, &ctrl](ev::Future<void, ::std::exception_ptr> f) {
185  // Propagate the exception, if any.
186  f.get().value();
187  // Resume CAN frame transmission.
188  ctrl.restart();
189  });
190 }
191 
192 void
194  ::std::function<void(io::CanState, io::CanState)> on_can_state) {
195  ::std::lock_guard<util::BasicLockable> lock(*this);
196  impl_->on_can_state = on_can_state;
197 }
198 
199 void
200 Node::OnCanError(::std::function<void(io::CanError)> on_can_error) {
201  ::std::lock_guard<util::BasicLockable> lock(*this);
202  impl_->on_can_error = on_can_error;
203 }
204 
205 void
207  ::std::lock_guard<util::BasicLockable> lock(*this);
208 
209  // Update the CAN network time before resetting the node. In the case of a
210  // master, this ensures that SDO timeouts do not occur too soon.
211  SetTime();
212 
213  if (impl_->nmt->csInd(CO_NMT_CS_RESET_NODE) == -1) util::throw_errc("Reset");
214 }
215 
216 void
217 Node::ConfigHeartbeat(uint8_t id, const ::std::chrono::milliseconds& ms,
218  ::std::error_code& ec) {
219  ::std::lock_guard<util::BasicLockable> lock(*this);
220 
221  auto ac = co_dev_cfg_hb(dev(), id, ms.count());
222 
223  if (ac)
224  ec = static_cast<SdoErrc>(ac);
225  else
226  ec.clear();
227 }
228 
229 void
230 Node::ConfigHeartbeat(uint8_t id, const ::std::chrono::milliseconds& ms) {
231  ::std::error_code ec;
232  ConfigHeartbeat(id, ms, ec);
233  if (ec) throw SdoError(Device::id(), 0x1016, 0, ec, "ConfigHeartbeat");
234 }
235 
236 void
237 Node::OnCommand(::std::function<void(NmtCommand)> on_command) {
238  ::std::lock_guard<util::BasicLockable> lock(*this);
239  impl_->on_command = on_command;
240 }
241 
242 void
243 Node::OnHeartbeat(::std::function<void(uint8_t, bool)> on_heartbeat) {
244  ::std::lock_guard<util::BasicLockable> lock(*this);
245  impl_->on_heartbeat = on_heartbeat;
246 }
247 
248 void
249 Node::OnState(::std::function<void(uint8_t, NmtState)> on_state) {
250  ::std::lock_guard<util::BasicLockable> lock(*this);
251  impl_->on_state = on_state;
252 }
253 
254 void
256  ::std::function<void(int, ::std::error_code, const void*, ::std::size_t)>
257  on_rpdo) {
258  ::std::lock_guard<util::BasicLockable> lock(*this);
259  impl_->on_rpdo = on_rpdo;
260 }
261 
262 void
263 Node::OnRpdoError(::std::function<void(int, uint16_t, uint8_t)> on_rpdo_error) {
264  ::std::lock_guard<util::BasicLockable> lock(*this);
265  impl_->on_rpdo_error = on_rpdo_error;
266 }
267 
268 void
270  ::std::function<void(int, ::std::error_code, const void*, ::std::size_t)>
271  on_tpdo) {
272  ::std::lock_guard<util::BasicLockable> lock(*this);
273  impl_->on_tpdo = on_tpdo;
274 }
275 
276 void
277 Node::OnSync(::std::function<void(uint8_t, const time_point&)> on_sync) {
278  ::std::lock_guard<util::BasicLockable> lock(*this);
279  impl_->on_sync = on_sync;
280 }
281 
282 void
283 Node::OnSyncError(::std::function<void(uint16_t, uint8_t)> on_sync_error) {
284  ::std::lock_guard<util::BasicLockable> lock(*this);
285  impl_->on_sync_error = on_sync_error;
286 }
287 
288 void
290  ::std::function<void(const ::std::chrono::system_clock::time_point&)>
291  on_time) {
292  ::std::lock_guard<util::BasicLockable> lock(*this);
293  impl_->on_time = on_time;
294 }
295 
296 void
298  ::std::function<void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy) {
299  ::std::lock_guard<util::BasicLockable> lock(*this);
300  impl_->on_emcy = on_emcy;
301 }
302 
303 void
305  ::std::function<void(int, ::std::chrono::milliseconds)> on_switch_bitrate) {
306  ::std::lock_guard<util::BasicLockable> lock(*this);
307  impl_->on_switch_bitrate = on_switch_bitrate;
308 }
309 
310 void
312  node->impl_->nmt->onTPDOEventLock();
313 }
314 
315 void
317  node->impl_->nmt->onTPDOEventUnlock();
318 }
319 
320 CANNet*
321 Node::net() const noexcept {
322  return *this;
323 }
324 
325 void
327  set_time();
328 }
329 
330 void
331 Node::OnCanState(io::CanState new_state, io::CanState old_state) noexcept {
332  assert(new_state != old_state);
333 
334  // TODO(jseldenthuis@lely.com): Clear EMCY in error active mode.
335  if (new_state == io::CanState::PASSIVE) {
336  // CAN in error passive mode.
337  Error(0x8120, 0x10);
338  } else if (old_state == io::CanState::BUSOFF) {
339  // Recovered from bus off.
340  Error(0x8140, 0x10);
341  }
342 }
343 
344 CONMT*
345 Node::nmt() const noexcept {
346  return impl_->nmt.get();
347 }
348 
349 void
350 Node::Error(uint16_t eec, uint8_t er, const uint8_t msef[5]) noexcept {
351  impl_->nmt->onErr(eec, er, msef);
352 }
353 
354 void
355 Node::RpdoRtr(int num) noexcept {
356  if (num) {
357  impl_->RpdoRtr(num);
358  } else {
359  for (num = 1; num <= 512; num++) impl_->RpdoRtr(num);
360  }
361 }
362 
363 void
364 Node::TpdoEvent(int num) noexcept {
365  impl_->nmt->onTPDOEvent(num);
366 }
367 
368 void
369 Node::on_can_state(io::CanState new_state, io::CanState old_state) noexcept {
370  OnCanState(new_state, old_state);
371  if (impl_->on_can_state) {
372  auto f = impl_->on_can_state;
374  f(new_state, old_state);
375  }
376 }
377 
378 void
380  OnCanError(error);
381  if (impl_->on_can_error) {
382  auto f = impl_->on_can_error;
384  f(error);
385  }
386 }
387 
388 void
389 Node::OnStore(uint8_t, int) {
390  util::throw_error_code("OnStore", ::std::errc::operation_not_supported);
391 }
392 
393 Node::Impl_::Impl_(Node* self_, CANNet* net, CODev* dev)
394  : self(self_), nmt(make_unique_c<CONMT>(net, dev)) {
395  nmt->setCsInd<Impl_, &Impl_::OnCsInd>(this);
396  nmt->setHbInd<Impl_, &Impl_::OnHbInd>(this);
397  nmt->setStInd<Impl_, &Impl_::OnStInd>(this);
398 
399  nmt->setSyncInd<Impl_, &Impl_::OnSyncInd>(this);
400 }
401 
402 void
403 Node::Impl_::OnCsInd(CONMT* nmt, uint8_t cs) noexcept {
404  if (cs == CO_NMT_CS_RESET_COMM) {
405  auto lss = nmt->getLSS();
406  if (lss) {
407  lss->setRateInd<Impl_, &Impl_::OnRateInd>(this);
408  lss->setStoreInd<Impl_, &Impl_::OnStoreInd>(this);
409  }
410  }
411 
412  if (cs == CO_NMT_CS_START || cs == CO_NMT_CS_ENTER_PREOP) {
413  auto sync = nmt->getSync();
414  if (sync) sync->setErr<Impl_, &Impl_::OnSyncErr>(this);
415  auto time = nmt->getTime();
416  if (time) time->setInd<Impl_, &Impl_::OnTimeInd>(this);
417  auto emcy = nmt->getEmcy();
418  if (emcy) emcy->setInd<Impl_, &Impl_::OnEmcyInd>(this);
419  }
420 
421  if (cs == CO_NMT_CS_START) {
422  for (int i = 1; i <= 512; i++) {
423  auto pdo = nmt->getRPDO(i);
424  if (pdo) {
425  pdo->setInd<Impl_, &Impl_::OnRpdoInd>(this);
426  pdo->setErr<Impl_, &Impl_::OnRpdoErr>(this);
427  }
428  }
429  for (int i = 1; i <= 512; i++) {
430  auto pdo = nmt->getTPDO(i);
431  if (pdo) pdo->setInd<Impl_, &Impl_::OnTpdoInd>(this);
432  }
433  }
434 
435  if (cs != CO_NMT_CS_RESET_NODE && cs != CO_NMT_CS_RESET_COMM) {
436  self->UpdateRpdoMapping();
437  self->UpdateTpdoMapping();
438  }
439 
440  self->OnCommand(static_cast<NmtCommand>(cs));
441 
442  if (on_command) {
443  auto f = on_command;
444  util::UnlockGuard<util::BasicLockable> unlock(*self);
445  f(static_cast<NmtCommand>(cs));
446  }
447 }
448 
449 void
450 Node::Impl_::OnHbInd(CONMT* nmt, uint8_t id, int state, int reason) noexcept {
451  // Invoke the default behavior before notifying the implementation.
452  nmt->onHb(id, state, reason);
453  // Only handle heartbeat timeout events. State changes are handled by OnSt().
454  if (reason != CO_NMT_EC_TIMEOUT) return;
455  // Notify the implementation.
456  bool occurred = state == CO_NMT_EC_OCCURRED;
457  self->OnHeartbeat(id, occurred);
458 
459  if (on_heartbeat) {
460  auto f = on_heartbeat;
461  util::UnlockGuard<util::BasicLockable> unlock(*self);
462  f(id, occurred);
463  }
464 }
465 
466 void
467 Node::Impl_::OnStInd(CONMT* nmt, uint8_t id, uint8_t st) noexcept {
468  // Invoke the default behavior before notifying the implementation.
469  nmt->onSt(id, st);
470  // Ignore local state changes.
471  if (id == nmt->getDev()->getId()) return;
472  // Notify the implementation.
473  self->OnState(id, static_cast<NmtState>(st));
474 
475  if (on_state) {
476  auto f = on_state;
477  util::UnlockGuard<util::BasicLockable> unlock(*self);
478  f(id, static_cast<NmtState>(st));
479  }
480 }
481 
482 void
483 Node::Impl_::OnRpdoInd(CORPDO* pdo, uint32_t ac, const void* ptr,
484  size_t n) noexcept {
485  int num = pdo->getNum();
486  self->OnRpdo(num, static_cast<SdoErrc>(ac), ptr, n);
487 
488  if (on_rpdo) {
489  auto f = on_rpdo;
490  util::UnlockGuard<util::BasicLockable> unlock(*self);
491  f(num, static_cast<SdoErrc>(ac), ptr, n);
492  }
493 }
494 
495 void
496 Node::Impl_::OnRpdoErr(CORPDO* pdo, uint16_t eec, uint8_t er) noexcept {
497  int num = pdo->getNum();
498  self->OnRpdoError(num, eec, er);
499 
500  if (on_rpdo_error) {
501  auto f = on_rpdo_error;
502  util::UnlockGuard<util::BasicLockable> unlock(*self);
503  f(num, eec, er);
504  }
505 }
506 
507 void
508 Node::Impl_::OnTpdoInd(COTPDO* pdo, uint32_t ac, const void* ptr,
509  size_t n) noexcept {
510  int num = pdo->getNum();
511  self->OnTpdo(num, static_cast<SdoErrc>(ac), ptr, n);
512 
513  if (on_tpdo) {
514  auto f = on_tpdo;
515  util::UnlockGuard<util::BasicLockable> unlock(*self);
516  f(num, static_cast<SdoErrc>(ac), ptr, n);
517  }
518 }
519 
520 void
521 Node::Impl_::OnSyncInd(CONMT*, uint8_t cnt) noexcept {
522  auto t = self->GetClock().gettime();
523  self->OnSync(cnt, t);
524 
525  if (on_sync) {
526  auto f = on_sync;
527  util::UnlockGuard<util::BasicLockable> unlock(*self);
528  f(cnt, t);
529  }
530 }
531 
532 void
533 Node::Impl_::OnSyncErr(COSync*, uint16_t eec, uint8_t er) noexcept {
534  self->OnSyncError(eec, er);
535 
536  if (on_sync_error) {
537  auto f = on_sync_error;
538  util::UnlockGuard<util::BasicLockable> unlock(*self);
539  f(eec, er);
540  }
541 }
542 
543 void
544 Node::Impl_::OnTimeInd(COTime*, const timespec* tp) noexcept {
545  assert(tp);
546  ::std::chrono::system_clock::time_point abs_time(util::from_timespec(*tp));
547  self->OnTime(abs_time);
548 
549  if (on_time) {
550  auto f = on_time;
551  util::UnlockGuard<util::BasicLockable> unlock(*self);
552  f(abs_time);
553  }
554 }
555 
556 void
557 Node::Impl_::OnEmcyInd(COEmcy*, uint8_t id, uint16_t ec, uint8_t er,
558  uint8_t msef[5]) noexcept {
559  self->OnEmcy(id, ec, er, msef);
560 
561  if (on_emcy) {
562  auto f = on_emcy;
563  util::UnlockGuard<util::BasicLockable> unlock(*self);
564  f(id, ec, er, msef);
565  }
566 }
567 
568 void
569 Node::Impl_::OnRateInd(COLSS*, uint16_t rate, int delay) noexcept {
570  self->OnSwitchBitrate(rate * 1000, ::std::chrono::milliseconds(delay));
571 
572  if (on_switch_bitrate) {
573  auto f = on_switch_bitrate;
574  util::UnlockGuard<util::BasicLockable> unlock(*self);
575  f(rate * 1000, ::std::chrono::milliseconds(delay));
576  }
577 }
578 
579 int
580 Node::Impl_::OnStoreInd(COLSS*, uint8_t id, uint16_t rate) noexcept {
581  try {
582  self->OnStore(id, rate * 1000);
583  return 0;
584  } catch (...) {
585  return -1;
586  }
587 }
588 
589 void
590 Node::Impl_::RpdoRtr(int num) noexcept {
591  auto pdo = nmt->getRPDO(num);
592  if (pdo) {
593  int errsv = get_errc();
594  pdo->rtr();
595  set_errc(errsv);
596  }
597 }
598 
599 } // namespace canopen
600 
601 } // namespace lely
lely::canopen::Node::OnRpdo
void OnRpdo(::std::function< void(int, ::std::error_code, const void *, ::std::size_t)> on_rpdo)
Registers the function to be invoked when a Receive-PDO is processed.
Definition: node.cpp:255
io_tqueue_wait::value
struct timespec value
The absolute expiration time.
Definition: tqueue.h:38
io_tqueue_submit_wait
void io_tqueue_submit_wait(io_tqueue_t *tq, struct io_tqueue_wait *wait)
Submits a wait operation to a timer queue.
Definition: tqueue.c:231
lely::canopen::Node::OnCanError
void OnCanError(::std::function< void(io::CanError)> on_can_error)
Registers the function to be invoked when an error is detected on the CAN bus.
Definition: node.cpp:200
lely::canopen::NmtCommand
NmtCommand
The NMT command specifiers.
Definition: node.hpp:42
ev_exec_t
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
lely::canopen::Node::AbortWait
bool AbortWait(io_tqueue_wait &wait) noexcept
Aborts the specified wait operation if it is pending.
Definition: node.cpp:155
lely::io::CanNet::set_time
void set_time()
Updates the CAN network time.
Definition: can_net.hpp:126
lely::canopen::Node::OnState
void OnState(::std::function< void(uint8_t, NmtState)> on_state)
Registers the function to be invoked whenan NMT state change or boot-up event is detected for a remot...
Definition: node.cpp:249
lely::canopen::Node::AsyncWait
ev::Future< void, ::std::exception_ptr > AsyncWait(ev_exec_t *exec, const time_point &t, io_tqueue_wait **pwait=nullptr)
Submits an asynchronous wait operation and creates a future which becomes ready once the wait operati...
Definition: node.cpp:132
dev.hpp
lely::io::TimerBase
A reference to an abstract timer.
Definition: timer.hpp:130
lely::canopen::Node::Impl_
The internal implementation of the CANopen node.
Definition: node.cpp:45
rpdo.hpp
tpdo.hpp
lely::util::UnlockGuard
A mutex wrapper that provides a convenient RAII-style mechanism for releasing a mutex for the duratio...
Definition: mutex.hpp:57
lely::canopen::Node::RpdoRtr
void RpdoRtr(int num=0) noexcept
Requests the transmission of a PDO by sending a CAN frame with the RTR (Remote Transmission Request) ...
Definition: node.cpp:355
node.hpp
lely::unique_c_ptr
::std::unique_ptr< T, delete_c_type< T > > unique_c_ptr
A specialization of std::unique_ptr for trivial, standard layout or incomplete C types,...
Definition: c_type.hpp:103
lely::io::ContextBase
A refence to an I/O context. This class is a wrapper around #io_ctx_t*.
Definition: ctx.hpp:49
lely::canopen::Node::Reset
void Reset()
(Re)starts the node.
Definition: node.cpp:206
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::error
The type of objects thrown as exceptions to report a system error with an associated error code.
Definition: exception.hpp:54
lely::CORPDO
An opaque CANopen Receive-PDO service type.
Definition: rpdo.hpp:65
lely::io::CanChannelBase
A reference to an abstract CAN channel.
Definition: can.hpp:429
lely::canopen::Node::OnCanState
void OnCanState(::std::function< void(io::CanState, io::CanState)> on_can_state)
Registers the function to be invoked when a CAN bus state change is detected.
Definition: node.cpp:193
nmt.hpp
lely::CONMT
An opaque CANopen NMT master/slave service type.
Definition: nmt.hpp:71
CO_NMT_EC_TIMEOUT
@ CO_NMT_EC_TIMEOUT
An NMT error control timeout event.
Definition: nmt.h:87
co_dev_cfg_hb
co_unsigned32_t co_dev_cfg_hb(co_dev_t *dev, co_unsigned8_t id, co_unsigned16_t ms)
Configures heartbeat consumption for the specified node by updating CANopen object 1016 (Consumer hea...
Definition: nmt.c:661
lely::canopen::Node::OnHeartbeat
void OnHeartbeat(::std::function< void(uint8_t, bool)> on_heartbeat)
Registers the function to be invoked when a heartbeat timeout event occurs or is resolved.
Definition: node.cpp:243
lely::io::CanNet::get_executor
ev::Executor get_executor() const noexcept
Definition: can_net.hpp:92
lely::canopen::Node::OnTime
void OnTime(::std::function< void(const ::std::chrono::system_clock::time_point &)> on_time)
Registers the function to be invoked when a TIME message is received.
Definition: node.cpp:289
lely::io::CanError
CanError
The error flags of a CAN bus, which are not mutually exclusive.
Definition: err.hpp:47
CO_NMT_CS_START
#define CO_NMT_CS_START
The NMT command specifier 'start'.
Definition: nmt.h:40
lely::io::CanState
CanState
The states of a CAN node, depending on the TX/RX error count.
Definition: err.hpp:33
lely::canopen::Node::on_can_state
void on_can_state(io::CanState new_state, io::CanState old_state) noexcept final
The function invoked when a CAN bus state change is detected.
Definition: node.cpp:369
lely::canopen::Node::TpdoEventMutex::unlock
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
Definition: node.cpp:316
lely::canopen::Node::OnStore
virtual void OnStore(uint8_t id, int bitrate)
The function invoked then a request is received from the LSS master to store the pending node-ID and ...
Definition: node.cpp:389
lely::io::CanControllerBase::stop
void stop(::std::error_code &ec) noexcept
Definition: can.hpp:293
lely::canopen::Node::TpdoEvent
void TpdoEvent(int num=0) noexcept
Triggers the transmission of an acyclic or event-driven PDO.
Definition: node.cpp:364
io_tqueue_wait
A wait operation suitable for use with a timer queue.
Definition: tqueue.h:36
io_tqueue_async_wait
ev_future_t * io_tqueue_async_wait(io_tqueue_t *tq, ev_exec_t *exec, const struct timespec *value, struct io_tqueue_wait **pwait)
Submits an asynchronous wait operation to a timer queue and creates a future which becomes ready once...
Definition: tqueue.c:326
lely::io::CanNet::get_clock
Clock get_clock() const noexcept
Definition: can_net.hpp:98
lely::COTPDO
An opaque CANopen Transmit-PDO service type.
Definition: tpdo.hpp:65
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::Device::id
uint8_t id() const noexcept
Returns the node-ID.
Definition: device.cpp:161
lely::COTime
An opaque CANopen TIME producer/consumer service type.
Definition: time.hpp:65
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
lely::COSync
An opaque CANopen SYNC producer/consumer service type.
Definition: sync.hpp:65
lely::ev::Executor
An abstract task executor. This class is a wrapper around #ev_exec_t*.
Definition: exec.hpp:38
lely::io::CanControllerBase::restart
void restart(::std::error_code &ec) noexcept
Definition: can.hpp:338
lely::canopen::Node::OnCommand
void OnCommand(::std::function< void(NmtCommand)> on_command)
Registers the function to be invoked when an NMT command is received from the master.
Definition: node.cpp:237
lely::io::CanControllerBase::set_bitrate
void set_bitrate(int nominal, int data, ::std::error_code &ec) noexcept
Definition: can.hpp:378
lely::canopen::Device::dev
CODev * dev() const noexcept
Returns a pointer to the internal CANopen device from <lely/co/dev.hpp>.
Definition: device.cpp:723
lely::ev::Future
A future.
Definition: future.hpp:50
lely::CANNet
An opaque CAN network interface type.
Definition: net.hpp:85
lely::canopen::Node::CancelWait
bool CancelWait(io_tqueue_wait &wait) noexcept
Cancels the specified wait operation if it is pending.
Definition: node.cpp:150
lely::canopen::Device
The CANopen device description.
Definition: device.hpp:45
CO_NMT_CS_ENTER_PREOP
#define CO_NMT_CS_ENTER_PREOP
The NMT command specifier 'enter pre-operational'.
Definition: nmt.h:46
lely::canopen::Node::OnSyncError
void OnSyncError(::std::function< void(uint16_t, uint8_t)> on_sync_error)
Registers the function to be invoked when the data length of a received SYNC message does not match.
Definition: node.cpp:283
lely::io::CanNet::get_ctx
ContextBase get_ctx() const noexcept
Definition: can_net.hpp:86
lely::canopen::Node::OnTpdo
void OnTpdo(::std::function< void(int, ::std::error_code, const void *, ::std::size_t)> on_tpdo)
Registers the function to be invoked after a Transmit-PDO is sent or an error occurs.
Definition: node.cpp:269
lely::canopen::Node::OnEmcy
void OnEmcy(::std::function< void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy)
Registers the function to be invoked when an EMCY message is received.
Definition: node.cpp:297
lely::ev::Future::get
result_type & get()
Returns the result of a ready future.
Definition: future.hpp:490
io_tqueue_abort_wait
size_t io_tqueue_abort_wait(io_tqueue_t *tq, struct io_tqueue_wait *wait)
Aborts the specified timer queue wait operation if it is pending.
Definition: tqueue.c:307
lely::io::CanNet::start
void start() noexcept
Definition: can_net.hpp:80
lely::canopen::SdoErrc
SdoErrc
The SDO abort codes.
Definition: sdo_error.hpp:42
lely::canopen::Node::GetContext
io::ContextBase GetContext() const noexcept
Returns the underlying I/O context with which this context is registered.
Definition: node.cpp:111
coapp.hpp
CO_NMT_EC_OCCURRED
@ CO_NMT_EC_OCCURRED
An NMT error control event occurred.
Definition: nmt.h:80
lely::canopen::Node::GetClock
io::Clock GetClock() const noexcept
Returns the clock used by the timer.
Definition: node.cpp:116
lely::canopen::Node::ConfigHeartbeat
void ConfigHeartbeat(uint8_t id, const ::std::chrono::milliseconds &ms, ::std::error_code &ec)
Configures heartbeat consumption for the specified node by updating CANopen object 1016 (Consumer hea...
Definition: node.cpp:217
lely::canopen::Node::net
CANNet * net() const noexcept
Returns a pointer to the internal CAN network interface from <lely/can/net.hpp>.
Definition: node.cpp:321
lely::canopen::Node
The base class for CANopen nodes.
Definition: node.hpp:115
lely::canopen::Node::GetExecutor
ev::Executor GetExecutor() const noexcept
Returns the executor used to process I/O and CANopen events.
Definition: node.cpp:106
CO_NMT_CS_RESET_NODE
#define CO_NMT_CS_RESET_NODE
The NMT command specifier 'reset node'.
Definition: nmt.h:49
lely::canopen::NmtState
NmtState
The NMT states.
Definition: node.hpp:56
lely::canopen::SdoError
The type of exception thrown when an SDO abort code is received.
Definition: sdo_error.hpp:121
lely::io::Clock
An abstract clock. This class is a wrapper around #io_clock_t*.
Definition: clock.hpp:35
lely::canopen::Node::OnSync
void OnSync(::std::function< void(uint8_t, const time_point &)> on_sync)
Registers the function to be invoked when a SYNC message is sent/received.
Definition: node.cpp:277
lely::io::CanNet::unlock
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
Definition: can_net.hpp:109
lss.hpp
lely::canopen::Node::Node
Node(ev_exec_t *exec, io::TimerBase &timer, io::CanChannelBase &chan, const ::std::string &dcf_txt, const ::std::string &dcf_bin="", uint8_t id=0xff)
Creates a new CANopen node.
Definition: node.cpp:92
lely::canopen::Node::on_can_error
void on_can_error(io::CanError error) noexcept final
The function invoked when an error is detected on the CAN bus.
Definition: node.cpp:379
lely::io::CanControllerBase
A reference to an abstract CAN controller.
Definition: can.hpp:285
lely::canopen::Node::SubmitWait
void SubmitWait(const time_point &t, io_tqueue_wait &wait)
Submits a wait operation.
Definition: node.cpp:121
lely::COLSS
An opaque CANopen LSS master/slave service type.
Definition: lss.hpp:66
io_tqueue_cancel_wait
size_t io_tqueue_cancel_wait(io_tqueue_t *tq, struct io_tqueue_wait *wait)
Cancels the specified timer queue wait operation if it is pending.
Definition: tqueue.c:288
lely::canopen::Node::SetTime
void SetTime()
Updates the CAN network time.
Definition: node.cpp:326
lely::COEmcy
An opaque CANopen EMCY producer/consumer service type.
Definition: emcy.hpp:65
emcy.hpp
lely::canopen::Node::TpdoEventMutex::lock
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: node.cpp:311
sync.hpp
CO_NMT_CS_RESET_COMM
#define CO_NMT_CS_RESET_COMM
The NMT command specifier 'reset communication'.
Definition: nmt.h:52
lely::canopen::Node::OnRpdoError
void OnRpdoError(::std::function< void(int, uint16_t, uint8_t)> on_rpdo_error)
Registers the function to be invoked when a Receive-PDO length mismatch or timeout error occurs.
Definition: node.cpp:263
time.hpp
lely::canopen::Node::OnSwitchBitrate
void OnSwitchBitrate(::std::function< void(int, ::std::chrono::milliseconds)> on_switch_bitrate)
Registers the function to be invoked when the LSS master activates the bit rate of all CANopen device...
Definition: node.cpp:304
lely::make_unique_c
unique_c_ptr< T > make_unique_c(Args &&... args)
Creates an instance of a trivial, standard layout or incomplete C type and wraps it in a lely::unique...
Definition: c_type.hpp:111
lely::canopen::Node::nmt
CONMT * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt....
Definition: node.cpp:345
lely::CODev
An opaque CANopen device type.
Definition: dev.hpp:77
lely::canopen::Node::AsyncSwitchBitrate
ev::Future< void, ::std::exception_ptr > AsyncSwitchBitrate(io::CanControllerBase &ctrl, int bitrate, ::std::chrono::milliseconds delay)
Stops the specified CAN controller and submits asynchronous operations to wait for the delay period,...
Definition: node.cpp:160