Lely core libraries  2.2.5
master.cpp
Go to the documentation of this file.
1 
24 #include "coapp.hpp"
25 
26 #if !LELY_NO_COAPP_MASTER
27 
28 #include <lely/coapp/driver.hpp>
29 
30 #include <algorithm>
31 #include <array>
32 #include <map>
33 #include <string>
34 
35 #include <cassert>
36 
37 #include <lely/co/dev.hpp>
38 #include <lely/co/nmt.hpp>
39 
40 namespace lely {
41 
42 namespace canopen {
43 
46  Impl_(BasicMaster* self, CONMT* nmt);
47 
48  ev::Future<void> AsyncDeconfig(DriverBase* driver);
49 
50  void OnNgInd(CONMT* nmt, uint8_t id, int state, int reason) noexcept;
51  void OnBootInd(CONMT* nmt, uint8_t id, uint8_t st, char es) noexcept;
52  void OnCfgInd(CONMT* nmt, uint8_t id, COCSDO* sdo) noexcept;
53 
54  BasicMaster* self;
55  ::std::function<void(uint8_t, bool)> on_node_guarding;
56  ::std::function<void(uint8_t, NmtState, char, const ::std::string&)> on_boot;
57  ::std::array<bool, CO_NUM_NODES> ready{{false}};
58  ::std::array<bool, CO_NUM_NODES> config{{false}};
59  ::std::map<uint8_t, Sdo> sdos;
60 };
61 
62 void
64  ::std::lock_guard<util::BasicLockable> lock(*node);
66 }
67 
68 void
70  ::std::lock_guard<util::BasicLockable> lock(*node);
72 }
73 
75  io::CanChannelBase& chan, const ::std::string& dcf_txt,
76  const ::std::string& dcf_bin, uint8_t id)
77  : Node(exec, timer, chan, dcf_txt, dcf_bin, id),
78  tpdo_event_mutex(*this),
79  impl_(new Impl_(this, Node::nmt())) {}
80 
81 BasicMaster::~BasicMaster() = default;
82 
83 bool
84 BasicMaster::Boot(uint8_t id) {
85  if (!id || id > CO_NUM_NODES) return false;
86 
87  ::std::lock_guard<util::BasicLockable> lock(*this);
88 
89  if (co_nmt_is_booting(nmt(), id)) return false;
90 
91  // Abort any ongoing or pending SDO requests for the slave, since the master
92  // MAY need the Client-SDO service for the NMT 'boot slave' process.
93  CancelSdo(id);
94 
95  auto ready = impl_->ready[id - 1];
96  impl_->ready[id - 1] = false;
97  if (co_nmt_boot_req(nmt(), id, co_nmt_get_timeout(nmt())) == -1) {
98  impl_->ready[id - 1] = ready;
99  util::throw_errc("Boot");
100  }
101 
102  return true;
103 }
104 
105 bool
106 BasicMaster::IsReady(uint8_t id) const {
107  if (!id || id > CO_NUM_NODES) return false;
108 
109  ::std::lock_guard<util::BasicLockable> lock(const_cast<BasicMaster&>(*this));
110  return impl_->ready[id - 1];
111 }
112 
115  {
116  ::std::lock_guard<util::BasicLockable> lock(*this);
117  auto it = find(id);
118  if (it != end()) return impl_->AsyncDeconfig(it->second);
119  }
120  return ev::make_empty_future();
121 }
122 
125  ::std::array<ev::Future<void>, CO_NUM_NODES> futures;
126  ::std::size_t n = 0;
127  {
128  ::std::lock_guard<util::BasicLockable> lock(*this);
129  for (const auto& it : *this) futures[n++] = impl_->AsyncDeconfig(it.second);
130  }
131  // Create a temporary array of pointers, since ev::Future is not guaranteed to
132  // be the same size as ev_future_t*.
133  ::std::array<ev_future_t*, CO_NUM_NODES> tmp;
134  ::std::copy_n(futures.begin(), n, tmp.begin());
135  return ev::when_all(GetExecutor(), n, tmp.data());
136 }
137 
138 void
139 BasicMaster::Error(uint8_t id) {
140  ::std::lock_guard<util::BasicLockable> lock(*this);
141 
142  if (nmt()->nodeErrInd(id) == -1) util::throw_errc("Error");
143 }
144 
145 void
146 BasicMaster::Error(uint16_t eec, uint8_t er, const uint8_t msef[5]) noexcept {
147  ::std::lock_guard<util::BasicLockable> lock(*this);
148 
149  Node::Error(eec, er, msef);
150 }
151 
152 void
154  ::std::lock_guard<util::BasicLockable> lock(*this);
155 
156  if (nmt()->csReq(static_cast<uint8_t>(cs), id) == -1)
157  util::throw_errc("Command");
158 }
159 
160 void
161 BasicMaster::RpdoRtr(int num) noexcept {
162  ::std::lock_guard<util::BasicLockable> lock(*this);
163 
164  Node::RpdoRtr(num);
165 }
166 
167 void
168 BasicMaster::TpdoEvent(int num) noexcept {
169  ::std::lock_guard<util::BasicLockable> lock(*this);
170 
171  Node::TpdoEvent(num);
172 }
173 
174 ::std::chrono::milliseconds
176  ::std::lock_guard<util::BasicLockable> lock(const_cast<BasicMaster&>(*this));
177 
178  return detail::from_sdo_timeout(nmt()->getTimeout());
179 }
180 
181 void
182 BasicMaster::SetTimeout(const ::std::chrono::milliseconds& timeout) {
183  ::std::lock_guard<util::BasicLockable> lock(*this);
184 
185  nmt()->setTimeout(detail::to_sdo_timeout(timeout));
186 }
187 
188 void
190  ::std::lock_guard<util::BasicLockable> lock(*this);
191 
192  if (!driver.id() || driver.id() > 0x7f)
193  throw ::std::out_of_range("invalid node-ID: " +
194  ::std::to_string(driver.id()));
195  if (driver.id() == nmt()->getDev()->getId())
196  throw ::std::out_of_range("cannot register node-ID of master: " +
197  ::std::to_string(driver.id()));
198  if (find(driver.id()) != end())
199  throw ::std::out_of_range("node-ID " + ::std::to_string(driver.id()) +
200  " already registered");
201 
202  MapType::operator[](driver.id()) = &driver;
203 }
204 
205 void
207  ::std::lock_guard<util::BasicLockable> lock(*this);
208 
209  auto id = driver.id();
210  auto it = find(id);
211  if (it != end() && it->second == &driver) {
212  CancelSdo(id);
213  erase(it);
214  }
215 }
216 
217 void
219  ::std::function<void(uint8_t, bool)> on_node_guarding) {
220  ::std::lock_guard<util::BasicLockable> lock(*this);
221  impl_->on_node_guarding = on_node_guarding;
222 }
223 
224 void
226  ::std::function<void(uint8_t, NmtState, char, const ::std::string&)>
227  on_boot) {
228  ::std::lock_guard<util::BasicLockable> lock(*this);
229  impl_->on_boot = on_boot;
230 }
231 
232 void
233 BasicMaster::IsReady(uint8_t id, bool ready) noexcept {
234  if (id && id <= CO_NUM_NODES) impl_->ready[id - 1] = ready;
235 }
236 
237 void
239  for (const auto& it : *this) {
241  it.second->OnCanError(error);
242  }
243 }
244 
245 void
247  io::CanState old_state) noexcept {
248  for (const auto& it : *this) {
250  it.second->OnCanState(new_state, old_state);
251  }
252 }
253 
254 void
255 BasicMaster::OnRpdoWrite(uint8_t id, uint16_t idx, uint8_t subidx) noexcept {
256  auto it = find(id);
257  if (it != end()) {
259  it->second->OnRpdoWrite(idx, subidx);
260  }
261 }
262 
263 void
265  // Abort all ongoing and pending SDO requests unless the master is in the
266  // pre-operational or operational state.
267  if (cs != NmtCommand::ENTER_PREOP && cs != NmtCommand::START) CancelSdo();
268  for (const auto& it : *this) {
270  it.second->OnCommand(cs);
271  }
272 }
273 
274 void
275 BasicMaster::OnNodeGuarding(uint8_t id, bool occurred) noexcept {
276  auto it = find(id);
277  if (it != end()) {
279  it->second->OnNodeGuarding(occurred);
280  }
281 }
282 
283 void
284 BasicMaster::OnHeartbeat(uint8_t id, bool occurred) noexcept {
285  auto it = find(id);
286  if (it != end()) {
288  it->second->OnHeartbeat(occurred);
289  }
290 }
291 
292 void
293 BasicMaster::OnState(uint8_t id, NmtState st) noexcept {
294  if (st == NmtState::BOOTUP && !IsConfig(id)) {
295  IsReady(id, false);
296  // Abort any ongoing or pending SDO requests for the slave, since the master
297  // MAY need the Client-SDO service for the NMT 'boot slave' process.
298  CancelSdo(id);
299  }
300  auto it = find(id);
301  if (it != end()) {
303  it->second->OnState(st);
304  }
305 }
306 
307 void
308 BasicMaster::OnBoot(uint8_t id, NmtState st, char es,
309  const ::std::string& what) noexcept {
310  auto it = find(id);
311  if (it != end()) {
313  it->second->OnBoot(st, es, what);
314  }
315 }
316 
317 void
318 BasicMaster::OnConfig(uint8_t id) noexcept {
319  auto it = find(id);
320  // If no remote interface is registered for this node, the 'update
321  // configuration' process is considered complete.
322  if (it == end()) {
323  ConfigResult(id, ::std::error_code());
324  return;
325  }
326  // Let the driver perform the configuration update.
328  it->second->OnConfig([this, id](::std::error_code ec) {
329  ::std::lock_guard<util::BasicLockable> lock(*this);
330  // Report the result of the 'update configuration' process.
331  ConfigResult(id, ec);
332  });
333 }
334 
335 void
336 BasicMaster::ConfigResult(uint8_t id, ::std::error_code ec) noexcept {
337  assert(id && id <= CO_NUM_NODES);
338  impl_->config[id - 1] = false;
339  if (nmt()->isBooting(id))
340  // Destroy the Client-SDO, since it will be taken over by the master.
341  impl_->sdos.erase(id);
342  // Ignore any errors, since we cannot handle them here.
343  nmt()->cfgRes(id, static_cast<uint32_t>(sdo_errc(ec)));
344 }
345 
346 void
347 BasicMaster::OnSync(uint8_t cnt, const time_point& t) noexcept {
348  for (const auto& it : *this) {
350  it.second->OnSync(cnt, t);
351  }
352 }
353 
354 void
355 BasicMaster::OnSyncError(uint16_t eec, uint8_t er) noexcept {
356  for (const auto& it : *this) {
358  it.second->OnSyncError(eec, er);
359  }
360 }
361 
362 void
364  const ::std::chrono::system_clock::time_point& abs_time) noexcept {
365  for (const auto& it : *this) {
367  it.second->OnTime(abs_time);
368  }
369 }
370 
371 void
372 BasicMaster::OnEmcy(uint8_t id, uint16_t eec, uint8_t er,
373  uint8_t msef[5]) noexcept {
374  auto it = find(id);
375  if (it != end()) {
377  it->second->OnEmcy(eec, er, msef);
378  }
379 }
380 
381 bool
382 BasicMaster::IsConfig(uint8_t id) const {
383  if (!id || id > CO_NUM_NODES) return false;
384 
385  return impl_->config[id - 1];
386 }
387 
388 Sdo*
389 BasicMaster::GetSdo(uint8_t id) {
390  if (!id || id > 0x7f)
391  throw ::std::out_of_range("invalid node-ID: " + ::std::to_string(id));
392  // The Client-SDO service only exists in the pre-operational and operational
393  // state.
394  auto st = nmt()->getSt();
395  if (st != CO_NMT_ST_PREOP && st != CO_NMT_ST_START) return nullptr;
396  // During the 'update configuration' step of the NMT 'boot slave' process, a
397  // Client-SDO queue may be available.
398  auto it = impl_->sdos.find(id);
399  if (it != impl_->sdos.end()) return &it->second;
400  // The master needs the Client-SDO service during the NMT 'boot slave'
401  // process.
402  if (nmt()->isBooting(id)) return nullptr;
403  // Return a Client-SDO queue for the default SDO.
404  return &(impl_->sdos[id] = Sdo(nmt()->getNet(), id));
405 }
406 
407 void
409  if (id)
410  impl_->sdos.erase(id);
411  else
412  impl_->sdos.clear();
413 }
414 
415 void
417  for (const auto& it : *this) {
418  DriverBase* driver = it.second;
419  driver->GetExecutor().post([=]() { driver->OnCanError(error); });
420  }
421 }
422 
423 void
425  io::CanState old_state) noexcept {
426  for (const auto& it : *this) {
427  DriverBase* driver = it.second;
428  driver->GetExecutor().post(
429  [=]() { driver->OnCanState(new_state, old_state); });
430  }
431 }
432 
433 void
434 AsyncMaster::OnRpdoWrite(uint8_t id, uint16_t idx, uint8_t subidx) noexcept {
435  auto it = find(id);
436  if (it != end()) {
437  DriverBase* driver = it->second;
438  driver->GetExecutor().post([=]() { driver->OnRpdoWrite(idx, subidx); });
439  }
440 }
441 
442 void
444  // Abort all ongoing and pending SDO requests unless the master is in the
445  // pre-operational or operational state.
446  if (cs != NmtCommand::ENTER_PREOP && cs != NmtCommand::START) CancelSdo();
447  for (const auto& it : *this) {
448  DriverBase* driver = it.second;
449  driver->GetExecutor().post([=]() { driver->OnCommand(cs); });
450  }
451 }
452 
453 void
454 AsyncMaster::OnNodeGuarding(uint8_t id, bool occurred) noexcept {
455  auto it = find(id);
456  if (it != end()) {
457  DriverBase* driver = it->second;
458  driver->GetExecutor().post([=]() { driver->OnNodeGuarding(occurred); });
459  }
460 }
461 
462 void
463 AsyncMaster::OnHeartbeat(uint8_t id, bool occurred) noexcept {
464  auto it = find(id);
465  if (it != end()) {
466  DriverBase* driver = it->second;
467  driver->GetExecutor().post([=]() { driver->OnHeartbeat(occurred); });
468  }
469 }
470 
471 void
472 AsyncMaster::OnState(uint8_t id, NmtState st) noexcept {
473  if (st == NmtState::BOOTUP && !IsConfig(id)) {
474  IsReady(id, false);
475  // Abort any ongoing or pending SDO requests for the slave, since the master
476  // MAY need the Client-SDO service for the NMT 'boot slave' process.
477  CancelSdo(id);
478  }
479  auto it = find(id);
480  if (it != end()) {
481  DriverBase* driver = it->second;
482  driver->GetExecutor().post([=]() { driver->OnState(st); });
483  }
484 }
485 
486 void
487 AsyncMaster::OnBoot(uint8_t id, NmtState st, char es,
488  const ::std::string& what) noexcept {
489  auto it = find(id);
490  if (it != end()) {
491  DriverBase* driver = it->second;
492  driver->GetExecutor().post([=]() { driver->OnBoot(st, es, what); });
493  }
494 }
495 
496 void
497 AsyncMaster::OnConfig(uint8_t id) noexcept {
498  auto it = find(id);
499  // If no remote interface is registered for this node, the 'update
500  // configuration' process is considered complete.
501  if (it == end()) {
502  ConfigResult(id, ::std::error_code());
503  return;
504  }
505 
506  // Let the driver perform the configuration update.
507  DriverBase* driver = it->second;
508  driver->GetExecutor().post([this, id, driver]() {
509  driver->OnConfig([this, id](::std::error_code ec) {
510  ::std::lock_guard<util::BasicLockable> lock(*this);
511  ConfigResult(id, ec);
512  });
513  });
514 }
515 
516 void
517 AsyncMaster::OnSync(uint8_t cnt, const time_point& t) noexcept {
518  for (const auto& it : *this) {
519  DriverBase* driver = it.second;
520  driver->GetExecutor().post([=]() { driver->OnSync(cnt, t); });
521  }
522 }
523 
524 void
525 AsyncMaster::OnSyncError(uint16_t eec, uint8_t er) noexcept {
526  for (const auto& it : *this) {
527  DriverBase* driver = it.second;
528  driver->GetExecutor().post([=]() { driver->OnSyncError(eec, er); });
529  }
530 }
531 
532 void
534  const ::std::chrono::system_clock::time_point& abs_time) noexcept {
535  for (const auto& it : *this) {
536  DriverBase* driver = it.second;
537  driver->GetExecutor().post([=]() { driver->OnTime(abs_time); });
538  }
539 }
540 
541 void
542 AsyncMaster::OnEmcy(uint8_t id, uint16_t eec, uint8_t er,
543  uint8_t msef[5]) noexcept {
544  ::std::array<uint8_t, 5> value = {0};
545  ::std::copy_n(msef, value.size(), value.begin());
546  auto it = find(id);
547  if (it != end()) {
548  DriverBase* driver = it->second;
549  driver->GetExecutor().post(
550  [=]() mutable { driver->OnEmcy(eec, er, value.data()); });
551  }
552 }
553 
554 BasicMaster::Impl_::Impl_(BasicMaster* self_, CONMT* nmt) : self(self_) {
555  nmt->setNgInd<Impl_, &Impl_::OnNgInd>(this);
556  nmt->setBootInd<Impl_, &Impl_::OnBootInd>(this);
557  nmt->setCfgInd<Impl_, &Impl_::OnCfgInd>(this);
558 }
559 
561 BasicMaster::Impl_::AsyncDeconfig(DriverBase* driver) {
562  self->IsReady(driver->id(), false);
564  driver->GetExecutor().post([=]() mutable {
565  driver->OnDeconfig([p](::std::error_code ec) mutable { p.set(ec); });
566  });
567  return p.get_future();
568 }
569 
570 void
571 BasicMaster::Impl_::OnNgInd(CONMT* nmt, uint8_t id, int state,
572  int reason) noexcept {
573  // Invoke the default behavior before notifying the implementation.
574  nmt->onNg(id, state, reason);
575  // Only handle node guarding timeout events. State changes are handled by
576  // OnSt().
577  if (reason != CO_NMT_EC_TIMEOUT) return;
578  // Notify the implementation.
579  bool occurred = state == CO_NMT_EC_OCCURRED;
580  self->OnNodeGuarding(id, occurred);
581  if (on_node_guarding) {
582  auto f = on_node_guarding;
583  util::UnlockGuard<util::BasicLockable> unlock(*self);
584  f(id, occurred);
585  }
586 }
587 
588 void
589 BasicMaster::Impl_::OnBootInd(CONMT*, uint8_t id, uint8_t st,
590  char es) noexcept {
591  if (id && id <= CO_NUM_NODES && (!es || es == 'L')) ready[id - 1] = true;
592  ::std::string what = es ? co_nmt_es2str(es) : "";
593  self->OnBoot(id, static_cast<NmtState>(st), es, what);
594  if (on_boot) {
595  auto f = on_boot;
596  util::UnlockGuard<util::BasicLockable> unlock(*self);
597  f(id, static_cast<NmtState>(st), es, what);
598  }
599 }
600 
601 void
602 BasicMaster::Impl_::OnCfgInd(CONMT*, uint8_t id, COCSDO* sdo) noexcept {
603  // Create a Client-SDO for the 'update configuration' process.
604  try {
605  sdos[id] = Sdo(sdo);
606  } catch (...) {
607  self->ConfigResult(id, SdoErrc::ERROR);
608  return;
609  }
610  config[id - 1] = true;
611  self->OnConfig(id);
612 }
613 
614 } // namespace canopen
615 
616 } // namespace lely
617 
618 #endif // !LELY_NO_COAPP_MASTER
lely::ev::Executor::post
void post(ev_task &task) noexcept
Definition: exec.hpp:75
lely::canopen::DriverBase
The abstract driver interface for a remote CANopen node.
Definition: driver.hpp:36
lely::COCSDO
An opaque CANopen Client-SDO service type.
Definition: csdo.hpp:156
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::BasicMaster
The CANopen master.
Definition: master.hpp:50
lely::canopen::DriverBase::OnState
virtual void OnState(NmtState st) noexcept=0
The function invoked when an NMT state change or boot-up event is detected for the remote node by the...
lely::canopen::NmtState::BOOTUP
@ BOOTUP
Boot-up.
dev.hpp
lely::canopen::BasicMaster::OnConfig
virtual void OnConfig(uint8_t id) noexcept
The function invoked when the 'update configuration' step is reached during the NMT 'boot slave' proc...
Definition: master.cpp:318
lely::canopen::DriverBase::OnSyncError
virtual void OnSyncError(uint16_t eec, uint8_t er) noexcept=0
The function invoked when the data length of a received SYNC message does not match.
lely::io::TimerBase
A reference to an abstract timer.
Definition: timer.hpp:130
lely::canopen::DriverBase::OnNodeGuarding
virtual void OnNodeGuarding(bool occurred) noexcept=0
The function invoked when a node guarding timeout event occurs or is resolved for the remote node.
lely::canopen::BasicMaster::tpdo_event_mutex
TpdoEventMutex tpdo_event_mutex
Definition: master.hpp:1079
lely::ev::Promise
A promise.
Definition: future.hpp:60
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
CO_NUM_NODES
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
lely::canopen::AsyncMaster::OnRpdoWrite
void OnRpdoWrite(uint8_t id, uint16_t idx, uint8_t subidx) noexcept override
The default implementation queues a notification for the driver registered for node id.
Definition: master.cpp:434
lely::canopen::BasicMaster::OnCanError
void OnCanError(io::CanError error) noexcept override
The default implementation notifies all registered drivers.
Definition: master.cpp:238
lely::canopen::BasicMaster::GetTimeout
::std::chrono::milliseconds GetTimeout() const
Returns the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
Definition: master.cpp:175
lely::canopen::BasicMaster::OnCanState
void OnCanState(io::CanState new_state, io::CanState old_state) noexcept override
The default implementation invokes lely::canopen::Node::OnCanState() and notifies each registered dri...
Definition: master.cpp:246
lely::canopen::BasicMaster::Erase
void Erase(DriverBase &driver)
Unregisters a driver for a remote CANopen node.
Definition: master.cpp:206
lely::canopen::DriverBase::OnTime
virtual void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept=0
The function invoked when a TIME message is received by the master.
lely::canopen::BasicMaster::Insert
void Insert(DriverBase &driver)
Registers a driver for a remote CANopen node.
Definition: master.cpp:189
lely::error
The type of objects thrown as exceptions to report a system error with an associated error code.
Definition: exception.hpp:54
lely::canopen::BasicMaster::Boot
bool Boot(uint8_t id)
Requests the NMT 'boot slave' process for the specified node.
Definition: master.cpp:84
lely::canopen::detail::from_sdo_timeout
inline ::std::chrono::milliseconds from_sdo_timeout(int timeout)
Converts an SDO timeout to a duration.
Definition: sdo.hpp:140
lely::canopen::BasicMaster::Error
void Error(uint8_t id)
Indicates the occurrence of an error event on a remote node and triggers the error handling process (...
Definition: master.cpp:139
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::DriverBase::OnCanState
virtual void OnCanState(io::CanState new_state, io::CanState old_state) noexcept=0
The function invoked when a CAN bus state change is detected.
lely::io::CanChannelBase
A reference to an abstract CAN channel.
Definition: can.hpp:429
nmt.hpp
lely::canopen::AsyncMaster::OnEmcy
void OnEmcy(uint8_t id, uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept override
The default implementation queues a notification for the driver registered for node id.
Definition: master.cpp:542
CO_NMT_ST_PREOP
#define CO_NMT_ST_PREOP
The NMT state 'pre-operational'.
Definition: nmt.h:70
lely::CONMT
An opaque CANopen NMT master/slave service type.
Definition: nmt.hpp:71
co_nmt_boot_req
int co_nmt_boot_req(co_nmt_t *nmt, co_unsigned8_t id, int timeout)
Requests the NMT 'boot slave' process for the specified node.
Definition: nmt.c:1632
CO_NMT_EC_TIMEOUT
@ CO_NMT_EC_TIMEOUT
An NMT error control timeout event.
Definition: nmt.h:87
lely::canopen::BasicMaster::OnNodeGuarding
void OnNodeGuarding(::std::function< void(uint8_t, bool)> on_node_guarding)
Registers the function invoked when a node guarding timeout event occurs or is resolved.
Definition: master.cpp:218
lely::canopen::DriverBase::id
virtual uint8_t id() const noexcept=0
Returns the node-ID.
lely::canopen::AsyncMaster::OnHeartbeat
void OnHeartbeat(uint8_t id, bool occurred) noexcept override
The default implementation queues a notification for the driver registered for node id.
Definition: master.cpp:463
lely::canopen::BasicMaster::OnSync
void OnSync(uint8_t cnt, const time_point &t) noexcept override
The default implementation notifies all registered drivers.
Definition: master.cpp:347
lely::io::CanError
CanError
The error flags of a CAN bus, which are not mutually exclusive.
Definition: err.hpp:47
lely::canopen::BasicMaster::OnTime
void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept override
The default implementation notifies all registered drivers.
Definition: master.cpp:363
lely::canopen::BasicMaster::OnCommand
void OnCommand(NmtCommand cs) noexcept override
The default implementation notifies all registered drivers.
Definition: master.cpp:264
lely::io::CanState
CanState
The states of a CAN node, depending on the TX/RX error count.
Definition: err.hpp:33
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::AsyncMaster::OnCommand
void OnCommand(NmtCommand cs) noexcept override
The default implementation queues a notification for all registered drivers.
Definition: master.cpp:443
lely::canopen::BasicMaster::OnBoot
void OnBoot(::std::function< void(uint8_t, NmtState, char, const ::std::string &)> on_boot)
Registers the function invoked when the NMT 'boot slave' process completes.
Definition: master.cpp:225
lely::canopen::Node::TpdoEvent
void TpdoEvent(int num=0) noexcept
Triggers the transmission of an acyclic or event-driven PDO.
Definition: node.cpp:364
lely::canopen::AsyncMaster::OnSyncError
void OnSyncError(uint16_t eec, uint8_t er) noexcept override
The default implementation queues a notification for all registered drivers.
Definition: master.cpp:525
co_nmt_es2str
const char * co_nmt_es2str(char es)
Returns a pointer to a string describing an NMT boot error status.
Definition: nmt.c:703
lely::canopen::BasicMaster::OnRpdoWrite
void OnRpdoWrite(uint8_t id, uint16_t idx, uint8_t subidx) noexcept override
The default implementation notifies the driver registered for node id.
Definition: master.cpp:255
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::BasicMaster::OnState
void OnState(uint8_t id, NmtState st) noexcept override
The default implementation notifies the driver registered for node id.
Definition: master.cpp:293
lely::canopen::Device::id
uint8_t id() const noexcept
Returns the node-ID.
Definition: device.cpp:161
lely::canopen::BasicMaster::TpdoEventMutex::unlock
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
Definition: master.cpp:69
lely::canopen::BasicMaster::RpdoRtr
void RpdoRtr(int num=0) noexcept
Definition: master.cpp:161
lely::canopen::AsyncMaster::OnBoot
void OnBoot(uint8_t id, NmtState st, char es, const ::std::string &what) noexcept override
The default implementation queues a notification for the driver registered for node id.
Definition: master.cpp:487
lely::canopen::BasicMaster::CancelSdo
void CancelSdo(uint8_t id=0)
Aborts any ongoing or pending SDO requests for the specified slave.
Definition: master.cpp:408
lely::ev::Future
A future.
Definition: future.hpp:50
lely::canopen::DriverBase::GetExecutor
virtual ev::Executor GetExecutor() const noexcept=0
Returns the executor used to execute event handlers for this driver, including SDO confirmation funct...
lely::canopen::DriverBase::OnEmcy
virtual void OnEmcy(uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept=0
The function invoked when an EMCY message is received from the remote node.
lely::canopen::DriverBase::OnBoot
virtual void OnBoot(NmtState st, char es, const ::std::string &what) noexcept=0
The function invoked when the NMT 'boot slave' process completes for the remote node.
lely::canopen::BasicMaster::ConfigResult
void ConfigResult(uint8_t id, ::std::error_code ec) noexcept
Reports the result of the 'update configuration' step to the NMT service.
Definition: master.cpp:336
driver.hpp
lely::canopen::BasicMaster::BasicMaster
BasicMaster(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 master.
Definition: master.cpp:74
coapp.hpp
CO_NMT_EC_OCCURRED
@ CO_NMT_EC_OCCURRED
An NMT error control event occurred.
Definition: nmt.h:80
lely::canopen::DriverBase::OnConfig
virtual void OnConfig(::std::function< void(::std::error_code ec)> res) noexcept=0
The function invoked when the 'update configuration' step is reached during the NMT 'boot slave' proc...
lely::canopen::AsyncMaster::OnState
void OnState(uint8_t id, NmtState st) noexcept override
The default implementation queues a notification for the driver registered for node id.
Definition: master.cpp:472
lely::canopen::AsyncMaster::OnConfig
void OnConfig(uint8_t id) noexcept override
The default implementation queues a notification for the driver registered for node id.
Definition: master.cpp:497
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
lely::canopen::BasicMaster::IsReady
bool IsReady(uint8_t id) const
Returns true if the remote node is ready (i.e., the NMT 'boot slave' process has successfully complet...
Definition: master.cpp:106
lely::canopen::NmtState
NmtState
The NMT states.
Definition: node.hpp:56
lely::canopen::BasicMaster::AsyncDeconfig
ev::Future<::std::size_t, void > AsyncDeconfig()
Queues the DriverBase::OnDeconfig() method for all registered drivers and creates a future which beco...
Definition: master.cpp:124
lely::io::CanNet::unlock
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
Definition: can_net.hpp:109
lely::canopen::BasicMaster::OnHeartbeat
void OnHeartbeat(uint8_t id, bool occurred) noexcept override
The default implementation notifies the driver registered for node id.
Definition: master.cpp:284
lely::canopen::BasicMaster::OnSyncError
void OnSyncError(uint16_t eec, uint8_t er) noexcept override
The default implementation notifies all registered drivers.
Definition: master.cpp:355
lely::canopen::DriverBase::OnSync
virtual void OnSync(uint8_t cnt, const time_point &t) noexcept=0
The function invoked when a SYNC message is sent/received by the master.
lely::canopen::BasicMaster::Impl_
The internal implementation of the CANopen master.
Definition: master.cpp:45
lely::canopen::AsyncMaster::OnSync
void OnSync(uint8_t cnt, const time_point &t) noexcept override
The default implementation queues a notification for all registered drivers.
Definition: master.cpp:517
lely::canopen::AsyncMaster::OnNodeGuarding
void OnNodeGuarding(uint8_t id, bool occurred) noexcept override
The default implementation queues a notification for all registered drivers.
Definition: master.cpp:454
lely::canopen::BasicMaster::GetSdo
Sdo * GetSdo(uint8_t id)
Returns a pointer to the default client-SDO service for the given node.
Definition: master.cpp:389
lely::canopen::BasicMaster::SetTimeout
void SetTimeout(const ::std::chrono::milliseconds &timeout)
Sets the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
Definition: master.cpp:182
lely::canopen::detail::to_sdo_timeout
int to_sdo_timeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
Definition: sdo.hpp:148
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
lely::canopen::BasicMaster::Command
void Command(NmtCommand cs, uint8_t id=0)
Issues an NMT command to a slave.
Definition: master.cpp:153
lely::canopen::sdo_errc
SdoErrc sdo_errc(::std::error_code ec)
Returns the SDO abort code corresponding to an error code.
Definition: sdo_error.cpp:180
lely::canopen::NmtCommand::START
@ START
Start.
CO_NMT_ST_START
#define CO_NMT_ST_START
The NMT state 'operational'.
Definition: nmt.h:61
lely::canopen::AsyncMaster::OnTime
void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept override
The default implementation queues a notification for all registered drivers.
Definition: master.cpp:533
lely::canopen::DriverBase::OnCanError
virtual void OnCanError(io::CanError error) noexcept=0
The function invoked when an error is detected on the CAN bus.
lely::canopen::AsyncMaster::OnCanState
void OnCanState(io::CanState new_state, io::CanState old_state) noexcept override
The default implementation invokes lely::canopen::Node::OnCanState() and queues a notification for ea...
Definition: master.cpp:424
lely::canopen::BasicMaster::IsConfig
bool IsConfig(uint8_t id) const
Returns true if the remote node is configuring (i.e., the 'update configuration' step of the NMT 'boo...
Definition: master.cpp:382
lely::canopen::DriverBase::OnCommand
virtual void OnCommand(NmtCommand cs) noexcept=0
The function invoked when an NMT state change occurs on the master.
lely::canopen::BasicMaster::TpdoEventMutex::lock
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: master.cpp:63
lely::canopen::SdoErrc::ERROR
@ ERROR
General error.
co_nmt_get_timeout
int co_nmt_get_timeout(const co_nmt_t *nmt)
Returns the default SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
Definition: nmt.c:1553
lely::canopen::NmtCommand::ENTER_PREOP
@ ENTER_PREOP
Enter pre-operational.
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::AsyncMaster::OnCanError
void OnCanError(io::CanError error) noexcept override
The default implementation queues a notification for all registered drivers.
Definition: master.cpp:416
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
co_nmt_is_booting
int co_nmt_is_booting(const co_nmt_t *nmt, co_unsigned8_t id)
Returns 1 if the NMT 'boot slave' process is currently running for the specified node,...
Definition: nmt.c:1687
lely::canopen::BasicMaster::OnEmcy
void OnEmcy(uint8_t id, uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept override
The default implementation notifies the driver registered for node id.
Definition: master.cpp:372
lely::canopen::DriverBase::OnHeartbeat
virtual void OnHeartbeat(bool occurred) noexcept=0
The function invoked when a heartbeat timeout event occurs or is resolved for the remote node.
lely::canopen::Sdo
A Client-SDO queue.
Definition: sdo.hpp:407
lely::canopen::BasicMaster::TpdoEvent
void TpdoEvent(int num=0) noexcept
Definition: master.cpp:168