Lely core libraries 2.3.4
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/co/dev.h>
29#include <lely/co/nmt.h>
30#include <lely/coapp/driver.hpp>
31
32#include <algorithm>
33#include <array>
34#include <map>
35#include <string>
36
37#include <cassert>
38
39namespace lely {
40
41namespace canopen {
42
46
48
49#if !LELY_NO_CO_NG
50 void OnNgInd(co_nmt_t* nmt, uint8_t id, int state, int reason) noexcept;
51#endif
52#if !LELY_NO_CO_NMT_BOOT
53 void OnBootInd(co_nmt_t* nmt, uint8_t id, uint8_t st, char es) noexcept;
54#endif
55#if !LELY_NO_CO_NMT_CFG
56 void OnCfgInd(co_nmt_t* nmt, uint8_t id, co_csdo_t* sdo) noexcept;
57#endif
58
59 BasicMaster* self;
60 ::std::function<void(uint8_t, bool)> on_node_guarding;
61 ::std::function<void(uint8_t, NmtState, char, const ::std::string&)> on_boot;
62 ::std::array<bool, CO_NUM_NODES> ready{{false}};
63#if !LELY_NO_CO_NMT_CFG
64 ::std::array<bool, CO_NUM_NODES> config{{false}};
65#endif
66 ::std::map<uint8_t, Sdo> sdos;
67};
68
69void
71 ::std::lock_guard<util::BasicLockable> lock(*node);
73}
74
75void
77 ::std::lock_guard<util::BasicLockable> lock(*node);
79}
80
82 io::CanChannelBase& chan, const ::std::string& dcf_txt,
83 const ::std::string& dcf_bin, uint8_t id)
84 : Node(exec, timer, chan, dcf_txt, dcf_bin, id),
85 tpdo_event_mutex(*this),
86 impl_(new Impl_(this, Node::nmt())) {}
87
88BasicMaster::~BasicMaster() = default;
89
90bool
92 if (!id || id > CO_NUM_NODES) return false;
93
94#if LELY_NO_CO_NMT_BOOT
95 return false;
96#else
97 ::std::lock_guard<util::BasicLockable> lock(*this);
98
99 if (co_nmt_is_booting(nmt(), id)) return false;
100
101 // Abort any ongoing or pending SDO requests for the slave, since the master
102 // MAY need the Client-SDO service for the NMT 'boot slave' process.
103 CancelSdo(id);
104
105 auto ready = impl_->ready[id - 1];
106 impl_->ready[id - 1] = false;
107 if (co_nmt_boot_req(nmt(), id, co_nmt_get_timeout(nmt())) == -1) {
108 impl_->ready[id - 1] = ready;
109 util::throw_errc("Boot");
110 }
111
112 return true;
113#endif
114}
115
116bool
118 if (!id || id > CO_NUM_NODES) return false;
119
120 ::std::lock_guard<util::BasicLockable> lock(const_cast<BasicMaster&>(*this));
121 return impl_->ready[id - 1];
122}
123
126 {
127 ::std::lock_guard<util::BasicLockable> lock(*this);
128 auto it = find(id);
129 if (it != end()) return impl_->AsyncDeconfig(it->second);
130 }
131 return ev::make_empty_future();
132}
133
136 ::std::array<ev::Future<void>, CO_NUM_NODES> futures;
137 ::std::size_t n = 0;
138 {
139 ::std::lock_guard<util::BasicLockable> lock(*this);
140 for (const auto& it : *this) futures[n++] = impl_->AsyncDeconfig(it.second);
141 }
142 // Create a temporary array of pointers, since ev::Future is not guaranteed to
143 // be the same size as ev_future_t*.
144 ::std::array<ev_future_t*, CO_NUM_NODES> tmp;
145 ::std::copy_n(futures.begin(), n, tmp.begin());
146 return ev::when_all(GetExecutor(), n, tmp.data());
147}
148
149void
151 ::std::lock_guard<util::BasicLockable> lock(*this);
152
153 if (co_nmt_node_err_ind(nmt(), id) == -1) util::throw_errc("Error");
154}
155
156void
157BasicMaster::Error(uint16_t eec, uint8_t er, const uint8_t msef[5]) noexcept {
158 ::std::lock_guard<util::BasicLockable> lock(*this);
159
160 Node::Error(eec, er, msef);
161}
162
163void
165 ::std::lock_guard<util::BasicLockable> lock(*this);
166
167 if (co_nmt_cs_req(nmt(), static_cast<uint8_t>(cs), id) == -1)
168 util::throw_errc("Command");
169}
170
171void
172BasicMaster::RpdoRtr(int num) noexcept {
173 ::std::lock_guard<util::BasicLockable> lock(*this);
174
175 Node::RpdoRtr(num);
176}
177
178void
179BasicMaster::TpdoEvent(int num) noexcept {
180 ::std::lock_guard<util::BasicLockable> lock(*this);
181
182 Node::TpdoEvent(num);
183}
184
185::std::chrono::milliseconds
187 ::std::lock_guard<util::BasicLockable> lock(const_cast<BasicMaster&>(*this));
188
190}
191
192void
193BasicMaster::SetTimeout(const ::std::chrono::milliseconds& timeout) {
194 ::std::lock_guard<util::BasicLockable> lock(*this);
195
197}
198
199void
201 ::std::error_code ec;
202 SubmitWriteDcf(id, req, ec);
203 if (ec) throw SdoError(id, req.idx, req.subidx, ec, "SubmitWriteDcf");
204}
205
206void
208 ::std::error_code& ec) {
209 ::std::lock_guard<BasicLockable> lock(*this);
210
211 ec.clear();
212 auto sdo = GetSdo(id);
213 if (sdo) {
214 SetTime();
215 sdo->SubmitDownloadDcf(req);
216 } else {
217 ec = SdoErrc::NO_SDO;
218 }
219}
220
223 const uint8_t* end,
224 const ::std::chrono::milliseconds& timeout) {
225 if (!exec) exec = GetExecutor();
226
227 ::std::lock_guard<BasicLockable> lock(*this);
228
229 auto sdo = GetSdo(id);
230 if (sdo) {
231 SetTime();
232 return sdo->AsyncDownloadDcf(exec, begin, end, timeout);
233 } else {
235 "AsyncWriteDcf");
236 }
237}
238
241 const ::std::chrono::milliseconds& timeout) {
242 if (!exec) exec = GetExecutor();
243
244 ::std::lock_guard<BasicLockable> lock(*this);
245
246 auto sdo = GetSdo(id);
247 if (sdo) {
248 SetTime();
249 return sdo->AsyncDownloadDcf(exec, path, timeout);
250 } else {
252 "AsyncWriteDcf");
253 }
254}
255
256void
258 ::std::lock_guard<util::BasicLockable> lock(*this);
259
260 if (!driver.id() || driver.id() > 0x7f)
261 throw ::std::out_of_range("invalid node-ID: " +
262 ::std::to_string(driver.id()));
263 if (driver.id() == co_dev_get_id(co_nmt_get_dev(nmt())))
264 throw ::std::out_of_range("cannot register node-ID of master: " +
265 ::std::to_string(driver.id()));
266 if (find(driver.id()) != end())
267 throw ::std::out_of_range("node-ID " + ::std::to_string(driver.id()) +
268 " already registered");
269
270 MapType::operator[](driver.id()) = &driver;
271}
272
273void
275 ::std::lock_guard<util::BasicLockable> lock(*this);
276
277 auto id = driver.id();
278 auto it = find(id);
279 if (it != end() && it->second == &driver) {
280 CancelSdo(id);
281 erase(it);
282 }
283}
284
285void
287 ::std::function<void(uint8_t, bool)> on_node_guarding) {
288 ::std::lock_guard<util::BasicLockable> lock(*this);
289 impl_->on_node_guarding = on_node_guarding;
290}
291
292void
294 ::std::function<void(uint8_t, NmtState, char, const ::std::string&)>
295 on_boot) {
296 ::std::lock_guard<util::BasicLockable> lock(*this);
297 impl_->on_boot = on_boot;
298}
299
300void
302 io::CanState old_state) noexcept {
303 for (const auto& it : *this) {
305 it.second->OnCanState(new_state, old_state);
306 }
307}
308
309void
311 for (const auto& it : *this) {
313 it.second->OnCanError(error);
314 }
315}
316
317void
319 auto it = find(id);
320 if (it != end()) {
322 it->second->OnRpdoWrite(idx, subidx);
323 }
324}
325
326void
328 // Abort all ongoing and pending SDO requests unless the master is in the
329 // pre-operational or operational state.
330 if (cs != NmtCommand::ENTER_PREOP && cs != NmtCommand::START) CancelSdo();
331 for (const auto& it : *this) {
333 it.second->OnCommand(cs);
334 }
335}
336
337void
339 auto it = find(id);
340 if (it != end()) {
342 it->second->OnHeartbeat(occurred);
343 }
344}
345
346void
348 if (st == NmtState::BOOTUP && !IsConfig(id)) {
349 IsReady(id, false);
350 // Abort any ongoing or pending SDO requests for the slave, since the master
351 // MAY need the Client-SDO service for the NMT 'boot slave' process.
352 CancelSdo(id);
353 }
354 auto it = find(id);
355 if (it != end()) {
357 it->second->OnState(st);
358 }
359}
360
361void
362BasicMaster::OnSync(uint8_t cnt, const time_point& t) noexcept {
363 for (const auto& it : *this) {
365 it.second->OnSync(cnt, t);
366 }
367}
368
369void
371 for (const auto& it : *this) {
373 it.second->OnSyncError(eec, er);
374 }
375}
376
377void
379 const ::std::chrono::system_clock::time_point& abs_time) noexcept {
380 for (const auto& it : *this) {
382 it.second->OnTime(abs_time);
383 }
384}
385
386void
388 uint8_t msef[5]) noexcept {
389 auto it = find(id);
390 if (it != end()) {
392 it->second->OnEmcy(eec, er, msef);
393 }
394}
395
396void
398 auto it = find(id);
399 if (it != end()) {
401 it->second->OnNodeGuarding(occurred);
402 }
403}
404
405void
407 const ::std::string& what) noexcept {
408 auto it = find(id);
409 if (it != end()) {
411 it->second->OnBoot(st, es, what);
412 }
413}
414
415void
416BasicMaster::IsReady(uint8_t id, bool ready) noexcept {
417 if (id && id <= CO_NUM_NODES) impl_->ready[id - 1] = ready;
418}
419
420void
422#if LELY_NO_CO_NMT_CFG
423 ConfigResult(id, ::std::error_code());
424#else
425 auto it = find(id);
426 // If no remote interface is registered for this node, the 'update
427 // configuration' process is considered complete.
428 if (it == end()) {
429 ConfigResult(id, ::std::error_code());
430 return;
431 }
432 // Let the driver perform the configuration update.
434 it->second->OnConfig([this, id](::std::error_code ec) {
435 ::std::lock_guard<util::BasicLockable> lock(*this);
436 // Report the result of the 'update configuration' process.
437 ConfigResult(id, ec);
438 });
439#endif
440}
441
442void
443BasicMaster::ConfigResult(uint8_t id, ::std::error_code ec) noexcept {
444 assert(id && id <= CO_NUM_NODES);
445
446#if LELY_NO_CO_NMT_CFG
447 (void)id;
448 (void)ec;
449#else
450 impl_->config[id - 1] = false;
451#if !LELY_NO_CO_NMT_BOOT
452 if (co_nmt_is_booting(nmt(), id))
453 // Destroy the Client-SDO, since it will be taken over by the master.
454 impl_->sdos.erase(id);
455#endif
456 // Ignore any errors, since we cannot handle them here.
457 co_nmt_cfg_res(nmt(), id, static_cast<uint32_t>(sdo_errc(ec)));
458#endif
459}
460
461bool
463 if (!id || id > CO_NUM_NODES) return false;
464
465#if LELY_NO_CO_NMT_CFG
466 return false;
467#else
468 return impl_->config[id - 1];
469#endif
470}
471
472Sdo*
474 if (!id || id > 0x7f)
475 throw ::std::out_of_range("invalid node-ID: " + ::std::to_string(id));
476 // The Client-SDO service only exists in the pre-operational and operational
477 // state.
478 auto st = co_nmt_get_st(nmt());
479 if (st != CO_NMT_ST_PREOP && st != CO_NMT_ST_START) return nullptr;
480 // During the 'update configuration' step of the NMT 'boot slave' process, a
481 // Client-SDO queue may be available.
482 auto it = impl_->sdos.find(id);
483 if (it != impl_->sdos.end()) return &it->second;
484#if !LELY_NO_CO_NMT_BOOT
485 // The master needs the Client-SDO service during the NMT 'boot slave'
486 // process.
487 if (co_nmt_is_booting(nmt(), id)) return nullptr;
488#endif
489 // Return a Client-SDO queue for the default SDO.
490 return &(impl_->sdos[id] = Sdo(co_nmt_get_net(nmt()), id));
491}
492
493void
495 if (id)
496 impl_->sdos.erase(id);
497 else
498 impl_->sdos.clear();
499}
500
501void
503 io::CanState old_state) noexcept {
504 for (const auto& it : *this) {
505 DriverBase* driver = it.second;
506 driver->GetExecutor().post(
507 [=]() { driver->OnCanState(new_state, old_state); });
508 }
509}
510
511void
513 for (const auto& it : *this) {
514 DriverBase* driver = it.second;
515 driver->GetExecutor().post([=]() { driver->OnCanError(error); });
516 }
517}
518
519void
521 auto it = find(id);
522 if (it != end()) {
523 DriverBase* driver = it->second;
524 driver->GetExecutor().post([=]() { driver->OnRpdoWrite(idx, subidx); });
525 }
526}
527
528void
530 // Abort all ongoing and pending SDO requests unless the master is in the
531 // pre-operational or operational state.
532 if (cs != NmtCommand::ENTER_PREOP && cs != NmtCommand::START) CancelSdo();
533 for (const auto& it : *this) {
534 DriverBase* driver = it.second;
535 driver->GetExecutor().post([=]() { driver->OnCommand(cs); });
536 }
537}
538
539void
541 auto it = find(id);
542 if (it != end()) {
543 DriverBase* driver = it->second;
544 driver->GetExecutor().post([=]() { driver->OnHeartbeat(occurred); });
545 }
546}
547
548void
550 if (st == NmtState::BOOTUP && !IsConfig(id)) {
551 IsReady(id, false);
552 // Abort any ongoing or pending SDO requests for the slave, since the master
553 // MAY need the Client-SDO service for the NMT 'boot slave' process.
554 CancelSdo(id);
555 }
556 auto it = find(id);
557 if (it != end()) {
558 DriverBase* driver = it->second;
559 driver->GetExecutor().post([=]() { driver->OnState(st); });
560 }
561}
562
563void
564AsyncMaster::OnSync(uint8_t cnt, const time_point& t) noexcept {
565 for (const auto& it : *this) {
566 DriverBase* driver = it.second;
567 driver->GetExecutor().post([=]() { driver->OnSync(cnt, t); });
568 }
569}
570
571void
573 for (const auto& it : *this) {
574 DriverBase* driver = it.second;
575 driver->GetExecutor().post([=]() { driver->OnSyncError(eec, er); });
576 }
577}
578
579void
581 const ::std::chrono::system_clock::time_point& abs_time) noexcept {
582 for (const auto& it : *this) {
583 DriverBase* driver = it.second;
584 driver->GetExecutor().post([=]() { driver->OnTime(abs_time); });
585 }
586}
587
588void
590 uint8_t msef[5]) noexcept {
591 ::std::array<uint8_t, 5> value = {0};
592 ::std::copy_n(msef, value.size(), value.begin());
593 auto it = find(id);
594 if (it != end()) {
595 DriverBase* driver = it->second;
596 driver->GetExecutor().post(
597 [=]() mutable { driver->OnEmcy(eec, er, value.data()); });
598 }
599}
600
601void
603 auto it = find(id);
604 if (it != end()) {
605 DriverBase* driver = it->second;
606 driver->GetExecutor().post([=]() { driver->OnNodeGuarding(occurred); });
607 }
608}
609
610void
612 const ::std::string& what) noexcept {
613 auto it = find(id);
614 if (it != end()) {
615 DriverBase* driver = it->second;
616 driver->GetExecutor().post([=]() { driver->OnBoot(st, es, what); });
617 }
618}
619
620void
622 auto it = find(id);
623 // If no remote interface is registered for this node, the 'update
624 // configuration' process is considered complete.
625 if (it == end()) {
626 ConfigResult(id, ::std::error_code());
627 return;
628 }
629
630 // Let the driver perform the configuration update.
631 DriverBase* driver = it->second;
632 driver->GetExecutor().post([this, id, driver]() {
633 driver->OnConfig([this, id](::std::error_code ec) {
634 ::std::lock_guard<util::BasicLockable> lock(*this);
635 ConfigResult(id, ec);
636 });
637 });
638}
639
640BasicMaster::Impl_::Impl_(BasicMaster* self_, co_nmt_t* nmt) : self(self_) {
641#if !LELY_NO_CO_NG
643 nmt,
644 [](co_nmt_t* nmt, uint8_t id, int state, int reason,
645 void* data) noexcept {
646 static_cast<Impl_*>(data)->OnNgInd(nmt, id, state, reason);
647 },
648 this);
649#endif
650
651#if !LELY_NO_CO_NMT_BOOT
653 nmt,
654 [](co_nmt_t* nmt, uint8_t id, uint8_t st, char es, void* data) noexcept {
655 static_cast<Impl_*>(data)->OnBootInd(nmt, id, st, es);
656 },
657 this);
658#endif
659
660#if !LELY_NO_CO_NMT_CFG
662 nmt,
663 [](co_nmt_t* nmt, uint8_t id, co_csdo_t* sdo, void* data) noexcept {
664 static_cast<Impl_*>(data)->OnCfgInd(nmt, id, sdo);
665 },
666 this);
667#endif
668}
669
670ev::Future<void>
671BasicMaster::Impl_::AsyncDeconfig(DriverBase* driver) {
672 self->IsReady(driver->id(), false);
673 ev::Promise<void> p;
674 driver->GetExecutor().post([=]() mutable {
675 driver->OnDeconfig([p](::std::error_code ec) mutable { p.set(ec); });
676 });
677 return p.get_future();
678}
679
680#if !LELY_NO_CO_NG
681void
682BasicMaster::Impl_::OnNgInd(co_nmt_t* nmt, uint8_t id, int state,
683 int reason) noexcept {
684 // Invoke the default behavior before notifying the implementation.
685 co_nmt_on_ng(nmt, id, state, reason);
686 // Only handle node guarding timeout events. State changes are handled by
687 // OnSt().
688 if (reason != CO_NMT_EC_TIMEOUT) return;
689 // Notify the implementation.
690 bool occurred = state == CO_NMT_EC_OCCURRED;
691 self->OnNodeGuarding(id, occurred);
692 if (on_node_guarding) {
693 auto f = on_node_guarding;
694 util::UnlockGuard<util::BasicLockable> unlock(*self);
695 f(id, occurred);
696 }
697}
698#endif
699
700#if !LELY_NO_CO_NMT_BOOT
701void
702BasicMaster::Impl_::OnBootInd(co_nmt_t*, uint8_t id, uint8_t st,
703 char es) noexcept {
704 if (id && id <= CO_NUM_NODES && (!es || es == 'L')) ready[id - 1] = true;
705 ::std::string what = es ? co_nmt_es2str(es) : "";
706 self->OnBoot(id, static_cast<NmtState>(st), es, what);
707 if (on_boot) {
708 auto f = on_boot;
709 util::UnlockGuard<util::BasicLockable> unlock(*self);
710 f(id, static_cast<NmtState>(st), es, what);
711 }
712}
713#endif
714
715#if !LELY_NO_CO_NMT_CFG
716void
717BasicMaster::Impl_::OnCfgInd(co_nmt_t*, uint8_t id, co_csdo_t* sdo) noexcept {
718 // Create a Client-SDO for the 'update configuration' process.
719 try {
720 sdos[id] = Sdo(sdo);
721 } catch (...) {
722 self->ConfigResult(id, SdoErrc::ERROR);
723 return;
724 }
725 config[id - 1] = true;
726 self->OnConfig(id);
727}
728#endif
729
730} // namespace canopen
731
732} // namespace lely
733
734#endif // !LELY_NO_COAPP_MASTER
A CANopen value.
Definition val.hpp:42
void OnCanState(::std::function< void(io::CanState, io::CanState)> on_can_state)
Definition master.hpp:1963
void OnTime(::std::function< void(const ::std::chrono::system_clock::time_point &)> on_time)
Definition master.hpp:2011
void OnCanError(::std::function< void(io::CanError)> on_can_error)
Definition master.hpp:1969
void OnNodeGuarding(::std::function< void(uint8_t, bool)> on_node_guarding)
Definition master.hpp:2025
void OnEmcy(::std::function< void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy)
Definition master.hpp:2018
void OnConfig(uint8_t id) noexcept override
The default implementation queues a notification for the driver registered for node id.
Definition master.cpp:621
void OnBoot(::std::function< void(uint8_t, NmtState, char, const ::std::string &)> on_boot)
Definition master.hpp:2031
void OnState(::std::function< void(uint8_t, NmtState)> on_state)
Definition master.hpp:1993
void OnSyncError(::std::function< void(uint16_t, uint8_t)> on_sync_error)
Definition master.hpp:2005
void OnRpdoWrite(::std::function< void(uint8_t, uint16_t, uint8_t)> on_rpdo_write)
Definition master.hpp:1975
void OnCommand(::std::function< void(NmtCommand)> on_command)
Definition master.hpp:1981
void OnSync(::std::function< void(uint8_t, const time_point &)> on_sync)
Definition master.hpp:1999
void OnHeartbeat(::std::function< void(uint8_t, bool)> on_heartbeat)
Definition master.hpp:1987
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition master.cpp:70
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
Definition master.cpp:76
The CANopen master.
Definition master.hpp:50
void OnState(::std::function< void(uint8_t, NmtState)> on_state)
Definition master.hpp:1691
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:462
void TpdoEvent(int num=0) noexcept
Definition master.cpp:179
void SubmitWriteDcf(uint8_t id, SdoDownloadDcfRequest &req)
Equivalent to SubmitWriteDcf(uint8_t id, SdoDownloadDcfRequest& req, ::std::error_code& ec),...
Definition master.cpp:200
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:135
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:421
void OnTime(::std::function< void(const ::std::chrono::system_clock::time_point &)> on_time)
Definition master.hpp:1709
void RpdoRtr(int num=0) noexcept
Definition master.cpp:172
void OnHeartbeat(::std::function< void(uint8_t, bool)> on_heartbeat)
Definition master.hpp:1685
void Command(NmtCommand cs, uint8_t id=0)
Issues an NMT command to a slave.
Definition master.cpp:164
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:81
void OnCanState(::std::function< void(io::CanState, io::CanState)> on_can_state)
Definition master.hpp:1661
void Erase(DriverBase &driver)
Unregisters a driver for a remote CANopen node.
Definition master.cpp:274
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:293
SdoFuture< void > AsyncWriteDcf(ev_exec_t *exec, uint8_t id, const uint8_t *begin, const uint8_t *end)
Equivalent to AsyncWriteDcf(ev_exec_t* exec, uint8_t id, const uint8_t* begin, const uint8_t* end,...
Definition master.hpp:1586
void Insert(DriverBase &driver)
Registers a driver for a remote CANopen node.
Definition master.cpp:257
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:150
bool Boot(uint8_t id)
Requests the NMT 'boot slave' process for the specified node.
Definition master.cpp:91
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:286
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:117
::std::chrono::milliseconds GetTimeout() const
Returns the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
Definition master.cpp:186
void OnEmcy(::std::function< void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy)
Definition master.hpp:1716
void SetTimeout(const ::std::chrono::milliseconds &timeout)
Sets the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
Definition master.cpp:193
void OnCanError(::std::function< void(io::CanError)> on_can_error)
Definition master.hpp:1667
TpdoEventMutex tpdo_event_mutex
Definition master.hpp:1740
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:443
void CancelSdo(uint8_t id=0)
Aborts any ongoing or pending SDO requests for the specified slave.
Definition master.cpp:494
void OnSync(::std::function< void(uint8_t, const time_point &)> on_sync)
Definition master.hpp:1697
void OnRpdoWrite(::std::function< void(uint8_t, uint16_t, uint8_t)> on_rpdo_write)
Definition master.hpp:1673
void OnCommand(::std::function< void(NmtCommand)> on_command)
Definition master.hpp:1679
Sdo * GetSdo(uint8_t id)
Returns a pointer to the default client-SDO service for the given node.
Definition master.cpp:473
void OnSyncError(::std::function< void(uint16_t, uint8_t)> on_sync_error)
Definition master.hpp:1703
uint8_t id() const noexcept
Returns the node-ID.
Definition device.cpp:193
The abstract driver interface for a remote CANopen node.
Definition driver.hpp:36
virtual void OnCommand(NmtCommand cs) noexcept=0
The function invoked when an NMT state change occurs on the master.
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.
virtual void OnNodeGuarding(bool occurred) noexcept=0
The function invoked when a node guarding timeout event occurs or is resolved for the remote node.
virtual void OnHeartbeat(bool occurred) noexcept=0
The function invoked when a heartbeat timeout event occurs or is resolved for the remote node.
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...
virtual void OnCanError(io::CanError error) noexcept=0
The function invoked when an error is detected on the CAN bus.
virtual ev::Executor GetExecutor() const noexcept=0
Returns the executor used to execute event handlers for this driver, including SDO confirmation funct...
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.
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.
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...
virtual uint8_t id() const noexcept=0
Returns the node-ID.
virtual void OnCanState(io::CanState new_state, io::CanState old_state) noexcept=0
The function invoked when a CAN bus state change is detected.
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.
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.
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition node.cpp:396
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
Definition node.cpp:403
The base class for CANopen nodes.
Definition node.hpp:116
void SetTime()
Updates the CAN network time.
Definition node.cpp:415
__co_nmt * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt....
Definition node.cpp:434
void TpdoEvent(int num=0) noexcept
Triggers the transmission of an acyclic or event-driven PDO.
Definition node.cpp:457
ev::Executor GetExecutor() const noexcept
Returns the executor used to process I/O and CANopen events.
Definition node.cpp:159
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:444
A series of SDO download (i.e., write) requests corresponding to the entries in a concise DCF.
Definition sdo.hpp:318
The type of exception thrown when an SDO abort code is received.
A Client-SDO queue.
Definition sdo.hpp:588
uint16_t idx
The object index.
Definition sdo.hpp:193
uint8_t subidx
The object sub-index.
Definition sdo.hpp:195
The type of objects thrown as exceptions to report a system error with an associated error code.
Definition exception.hpp:54
A future.
Definition future.hpp:384
A reference to an abstract CAN channel.
Definition can.hpp:430
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
Definition can_net.hpp:109
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition can_net.hpp:104
A reference to an abstract timer.
Definition timer.hpp:130
A mutex wrapper that provides a convenient RAII-style mechanism for releasing a mutex for the duratio...
Definition mutex.hpp:57
This header file is part of the CANopen library; it contains the device description declarations.
co_unsigned8_t co_dev_get_id(const co_dev_t *dev)
Returns the node-ID of a CANopen device.
Definition dev.c:197
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition dev.h:56
This is the internal header file of the C++ CANopen application library.
This header file is part of the C++ CANopen application library; it contains the remote node driver i...
CanError
The error flags of a CAN bus, which are not mutually exclusive.
Definition err.hpp:47
CanState
The states of a CAN node, depending on the TX/RX error count.
Definition err.hpp:33
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition ev.h:29
inline ::std::chrono::milliseconds from_sdo_timeout(int timeout)
Converts an SDO timeout to a duration.
Definition sdo.hpp:140
int to_sdo_timeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
Definition sdo.hpp:148
NmtState
The NMT states.
Definition node.hpp:56
@ ERROR
General error.
@ NO_SDO
Resource not available: SDO connection.
SdoErrc sdo_errc(::std::error_code ec)
Returns the SDO abort code corresponding to an error code.
NmtCommand
The NMT command specifiers.
Definition node.hpp:42
@ ENTER_PREOP
Enter pre-operational.
This header file is part of the CANopen library; it contains the network management (NMT) declaration...
const char * co_nmt_es2str(char es)
Returns a pointer to a string describing an NMT boot error status.
Definition nmt.c:786
void co_nmt_set_cfg_ind(co_nmt_t *nmt, co_nmt_cfg_ind_t *ind, void *data)
Sets the indication function invoked when a CANopen NMT 'configuration request' process is received.
Definition nmt.c:1537
#define CO_NMT_ST_PREOP
The NMT state 'pre-operational'.
Definition nmt.h:70
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:1790
void co_nmt_set_boot_ind(co_nmt_t *nmt, co_nmt_boot_ind_t *ind, void *data)
Sets the indication function invoked when a CANopen NMT 'boot slave' process completes.
Definition nmt.c:1513
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:1929
can_net_t * co_nmt_get_net(const co_nmt_t *nmt)
Returns a pointer to the CAN network of an NMT master/slave service.
Definition nmt.c:1267
co_dev_t * co_nmt_get_dev(const co_nmt_t *nmt)
Returns a pointer to the CANopen device of an NMT master/slave service.
Definition nmt.c:1275
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:1871
@ CO_NMT_EC_TIMEOUT
An NMT error control timeout event.
Definition nmt.h:87
#define CO_NMT_ST_START
The NMT state 'operational'.
Definition nmt.h:61
co_unsigned8_t co_nmt_get_st(const co_nmt_t *nmt)
Returns the current state of a CANopen NMT service (one of CO_NMT_ST_BOOTUP, CO_NMT_ST_STOP,...
Definition nmt.c:1766
int co_nmt_cfg_res(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned32_t ac)
Indicates the result of the 'update configuration' step of an NMT 'request configuration' request for...
Definition nmt.c:2040
void co_nmt_set_timeout(co_nmt_t *nmt, int timeout)
Sets the default SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
Definition nmt.c:1798
int co_nmt_node_err_ind(co_nmt_t *nmt, co_unsigned8_t id)
Indicates the occurrence of an error event and triggers the error handling process (see Fig.
Definition nmt.c:2132
void co_nmt_set_ng_ind(co_nmt_t *nmt, co_nmt_ng_ind_t *ind, void *data)
Sets the indication function invoked when a node guarding event occurs.
Definition nmt.c:1318
int co_nmt_cs_req(co_nmt_t *nmt, co_unsigned8_t cs, co_unsigned8_t id)
Submits an NMT request to a slave.
Definition nmt.c:1806
void co_nmt_on_ng(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason)
Implements the default behavior when a node guarding event occurs (see sections 7....
Definition nmt.c:1327
@ CO_NMT_EC_OCCURRED
An NMT error control event occurred.
Definition nmt.h:80
A CANopen Client-SDO.
Definition csdo.c:71
A CANopen NMT master/slave service.
Definition nmt.c:148
The internal implementation of the CANopen master.
Definition master.cpp:44