Lely core libraries
2.3.4
|
Go to the documentation of this file.
26 #if !LELY_NO_COAPP_MASTER
50 void OnNgInd(
co_nmt_t*
nmt, uint8_t
id,
int state,
int reason) noexcept;
52 #if !LELY_NO_CO_NMT_BOOT
53 void OnBootInd(
co_nmt_t*
nmt, uint8_t
id, uint8_t st,
char es) noexcept;
55 #if !LELY_NO_CO_NMT_CFG
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}};
66 ::std::map<uint8_t, Sdo> sdos;
71 ::std::lock_guard<util::BasicLockable>
lock(*node);
77 ::std::lock_guard<util::BasicLockable>
lock(*node);
83 const ::std::string& dcf_bin, uint8_t
id)
84 :
Node(exec, timer, chan, dcf_txt, dcf_bin,
id),
88 BasicMaster::~BasicMaster() =
default;
94 #if LELY_NO_CO_NMT_BOOT
97 ::std::lock_guard<util::BasicLockable>
lock(*
this);
105 auto ready = impl_->ready[
id - 1];
106 impl_->ready[
id - 1] =
false;
108 impl_->ready[
id - 1] = ready;
109 util::throw_errc(
"Boot");
120 ::std::lock_guard<util::BasicLockable>
lock(
const_cast<BasicMaster&
>(*
this));
121 return impl_->ready[
id - 1];
127 ::std::lock_guard<util::BasicLockable>
lock(*
this);
129 if (it != end())
return impl_->AsyncDeconfig(it->second);
131 return ev::make_empty_future();
139 ::std::lock_guard<util::BasicLockable>
lock(*
this);
140 for (
const auto& it : *
this) futures[n++] = impl_->AsyncDeconfig(it.second);
144 ::std::array<ev_future_t*, CO_NUM_NODES> tmp;
145 ::std::copy_n(futures.begin(), n, tmp.begin());
151 ::std::lock_guard<util::BasicLockable>
lock(*
this);
158 ::std::lock_guard<util::BasicLockable> lock(*
this);
160 Node::Error(eec, er, msef);
165 ::std::lock_guard<util::BasicLockable>
lock(*
this);
168 util::throw_errc(
"Command");
173 ::std::lock_guard<util::BasicLockable> lock(*
this);
180 ::std::lock_guard<util::BasicLockable> lock(*
this);
185 ::std::chrono::milliseconds
187 ::std::lock_guard<util::BasicLockable>
lock(
const_cast<BasicMaster&
>(*
this));
194 ::std::lock_guard<util::BasicLockable>
lock(*
this);
201 ::std::error_code ec;
208 ::std::error_code& ec) {
209 ::std::lock_guard<BasicLockable>
lock(*
this);
215 sdo->SubmitDownloadDcf(req);
224 const ::std::chrono::milliseconds& timeout) {
227 ::std::lock_guard<BasicLockable>
lock(*
this);
232 return sdo->AsyncDownloadDcf(exec, begin, end, timeout);
241 const ::std::chrono::milliseconds& timeout) {
244 ::std::lock_guard<BasicLockable>
lock(*
this);
249 return sdo->AsyncDownloadDcf(exec, path, timeout);
258 ::std::lock_guard<util::BasicLockable>
lock(*
this);
260 if (!driver.
id() || driver.
id() > 0x7f)
261 throw ::std::out_of_range(
"invalid node-ID: " +
262 ::std::to_string(driver.
id()));
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");
270 MapType::operator[](driver.
id()) = &driver;
275 ::std::lock_guard<util::BasicLockable>
lock(*
this);
277 auto id = driver.
id();
279 if (it != end() && it->second == &driver) {
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;
294 ::std::function<
void(uint8_t,
NmtState,
char, const ::std::string&)>
296 ::std::lock_guard<util::BasicLockable>
lock(*
this);
297 impl_->on_boot = on_boot;
303 for (
const auto& it : *
this) {
305 it.second->OnCanState(new_state, old_state);
311 for (
const auto& it : *
this) {
313 it.second->OnCanError(
error);
322 it->second->OnRpdoWrite(idx, subidx);
331 for (
const auto& it : *
this) {
333 it.second->OnCommand(cs);
342 it->second->OnHeartbeat(occurred);
357 it->second->OnState(st);
363 for (
const auto& it : *
this) {
365 it.second->OnSync(cnt, t);
371 for (
const auto& it : *
this) {
373 it.second->OnSyncError(eec, er);
379 const ::std::chrono::system_clock::time_point& abs_time) noexcept {
380 for (
const auto& it : *
this) {
382 it.second->OnTime(abs_time);
388 uint8_t msef[5]) noexcept {
392 it->second->OnEmcy(eec, er, msef);
401 it->second->OnNodeGuarding(occurred);
407 const ::std::string& what) noexcept {
411 it->second->OnBoot(st, es, what);
417 if (
id &&
id <=
CO_NUM_NODES) impl_->ready[
id - 1] = ready;
422 #if LELY_NO_CO_NMT_CFG
423 ConfigResult(
id, ::std::error_code());
429 ConfigResult(
id, ::std::error_code());
434 it->second->OnConfig([
this,
id](::std::error_code ec) {
435 ::std::lock_guard<util::BasicLockable> lock(*
this);
437 ConfigResult(
id, ec);
446 #if LELY_NO_CO_NMT_CFG
450 impl_->config[
id - 1] =
false;
451 #if !LELY_NO_CO_NMT_BOOT
454 impl_->sdos.erase(
id);
465 #if LELY_NO_CO_NMT_CFG
468 return impl_->config[
id - 1];
474 if (!
id ||
id > 0x7f)
475 throw ::std::out_of_range(
"invalid node-ID: " + ::std::to_string(
id));
482 auto it = impl_->sdos.find(
id);
483 if (it != impl_->sdos.end())
return &it->second;
484 #if !LELY_NO_CO_NMT_BOOT
496 impl_->sdos.erase(
id);
504 for (
const auto& it : *
this) {
507 [=]() { driver->
OnCanState(new_state, old_state); });
513 for (
const auto& it : *
this) {
524 driver->
GetExecutor().
post([=]() { driver->OnRpdoWrite(idx, subidx); });
533 for (
const auto& it : *
this) {
565 for (
const auto& it : *
this) {
573 for (
const auto& it : *
this) {
581 const ::std::chrono::system_clock::time_point& abs_time) noexcept {
582 for (
const auto& it : *
this) {
590 uint8_t msef[5]) noexcept {
591 ::std::array<uint8_t, 5> value = {0};
592 ::std::copy_n(msef, value.size(), value.begin());
597 [=]()
mutable { driver->
OnEmcy(eec, er, value.data()); });
612 const ::std::string& what) noexcept {
626 ConfigResult(
id, ::std::error_code());
633 driver->
OnConfig([
this,
id](::std::error_code ec) {
634 ::std::lock_guard<util::BasicLockable> lock(*
this);
635 ConfigResult(
id, ec);
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);
651 #if !LELY_NO_CO_NMT_BOOT
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);
660 #if !LELY_NO_CO_NMT_CFG
664 static_cast<Impl_*
>(data)->OnCfgInd(
nmt,
id, sdo);
671 BasicMaster::Impl_::AsyncDeconfig(DriverBase* driver) {
672 self->IsReady(driver->id(),
false);
674 driver->GetExecutor().post([=]()
mutable {
675 driver->OnDeconfig([p](::std::error_code ec)
mutable { p.set(ec); });
677 return p.get_future();
682 BasicMaster::Impl_::OnNgInd(
co_nmt_t*
nmt, uint8_t
id,
int state,
683 int reason) noexcept {
691 self->OnNodeGuarding(
id, occurred);
692 if (on_node_guarding) {
693 auto f = on_node_guarding;
694 util::UnlockGuard<util::BasicLockable>
unlock(*
self);
700 #if !LELY_NO_CO_NMT_BOOT
702 BasicMaster::Impl_::OnBootInd(
co_nmt_t*, uint8_t
id, uint8_t st,
704 if (
id &&
id <=
CO_NUM_NODES && (!es || es ==
'L')) ready[
id - 1] =
true;
706 self->OnBoot(
id,
static_cast<NmtState>(st), es, what);
709 util::UnlockGuard<util::BasicLockable>
unlock(*
self);
710 f(
id,
static_cast<NmtState>(st), es, what);
715 #if !LELY_NO_CO_NMT_CFG
725 config[
id - 1] =
true;
734 #endif // !LELY_NO_COAPP_MASTER
void OnBoot(::std::function< void(uint8_t, NmtState, char, const ::std::string &)> on_boot)
void post(ev_task &task) noexcept
The abstract driver interface for a remote CANopen node.
NmtCommand
The NMT command specifiers.
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
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...
void SubmitWriteDcf(uint8_t id, SdoDownloadDcfRequest &req)
Equivalent to SubmitWriteDcf(uint8_t id, SdoDownloadDcfRequest& req, ::std::error_code& ec),...
virtual void OnConfig(uint8_t id) noexcept
The function invoked when the 'update configuration' step is reached during the NMT 'boot slave' proc...
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.
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.
A reference to an abstract timer.
virtual void OnNodeGuarding(bool occurred) noexcept=0
The function invoked when a node guarding timeout event occurs or is resolved for the remote node.
TpdoEventMutex tpdo_event_mutex
A mutex wrapper that provides a convenient RAII-style mechanism for releasing a mutex for the duratio...
void RpdoRtr(int num=0) noexcept
Requests the transmission of a PDO by sending a CAN frame with the RTR (Remote Transmission Request) ...
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
void OnRpdoWrite(::std::function< void(uint8_t, uint16_t, uint8_t)> on_rpdo_write)
::std::chrono::milliseconds GetTimeout() const
Returns the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
void Erase(DriverBase &driver)
Unregisters a driver for a remote CANopen node.
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.
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....
co_unsigned8_t co_dev_get_id(const co_dev_t *dev)
Returns the node-ID of a CANopen device.
void Insert(DriverBase &driver)
Registers a driver for a remote CANopen node.
The type of objects thrown as exceptions to report a system error with an associated error code.
bool Boot(uint8_t id)
Requests the NMT 'boot slave' process for the specified node.
void OnState(::std::function< void(uint8_t, NmtState)> on_state)
inline ::std::chrono::milliseconds from_sdo_timeout(int timeout)
Converts an SDO timeout to a duration.
void Error(uint8_t id)
Indicates the occurrence of an error event on a remote node and triggers the error handling process (...
virtual void OnCanState(io::CanState new_state, io::CanState old_state) noexcept=0
The function invoked when a CAN bus state change is detected.
A reference to an abstract CAN channel.
#define CO_NMT_ST_PREOP
The NMT state 'pre-operational'.
int co_nmt_cs_req(co_nmt_t *nmt, co_unsigned8_t cs, co_unsigned8_t id)
Submits an NMT request to a slave.
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.
@ CO_NMT_EC_TIMEOUT
An NMT error control timeout event.
void OnCommand(::std::function< void(NmtCommand)> on_command)
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.
virtual uint8_t id() const noexcept=0
Returns the node-ID.
void OnRpdoWrite(::std::function< void(uint8_t, uint16_t, uint8_t)> on_rpdo_write)
CanError
The error flags of a CAN bus, which are not mutually exclusive.
A series of SDO download (i.e., write) requests corresponding to the entries in a concise DCF.
uint16_t idx
The object index.
CanState
The states of a CAN node, depending on the TX/RX error count.
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
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.
void TpdoEvent(int num=0) noexcept
Triggers the transmission of an acyclic or event-driven PDO.
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,...
const char * co_nmt_es2str(char es)
Returns a pointer to a string describing an NMT boot error status.
void OnCommand(::std::function< void(NmtCommand)> on_command)
void OnSyncError(::std::function< void(uint16_t, uint8_t)> on_sync_error)
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process,...
uint8_t id() const noexcept
Returns the node-ID.
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
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.
void OnHeartbeat(::std::function< void(uint8_t, bool)> on_heartbeat)
void RpdoRtr(int num=0) noexcept
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,...
void OnHeartbeat(::std::function< void(uint8_t, bool)> on_heartbeat)
void CancelSdo(uint8_t id=0)
Aborts any ongoing or pending SDO requests for the specified slave.
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.
void OnTime(::std::function< void(const ::std::chrono::system_clock::time_point &)> on_time)
void OnSync(::std::function< void(uint8_t, const time_point &)> on_sync)
virtual ev::Executor GetExecutor() const noexcept=0
Returns the executor used to execute event handlers for this driver, including SDO confirmation funct...
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 ConfigResult(uint8_t id, ::std::error_code ec) noexcept
Reports the result of the 'update configuration' step to the NMT service.
A CANopen NMT master/slave service.
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.
@ CO_NMT_EC_OCCURRED
An NMT error control event occurred.
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...
void OnCanState(::std::function< void(io::CanState, io::CanState)> on_can_state)
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...
void OnConfig(uint8_t id) noexcept override
The default implementation queues a notification for the driver registered for node id.
The base class for CANopen nodes.
ev::Executor GetExecutor() const noexcept
Returns the executor used to process I/O and CANopen events.
void OnEmcy(::std::function< void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy)
bool IsReady(uint8_t id) const
Returns true if the remote node is ready (i.e., the NMT 'boot slave' process has successfully complet...
The type of exception thrown when an SDO abort code is received.
ev::Future<::std::size_t, void > AsyncDeconfig()
Queues the DriverBase::OnDeconfig() method for all registered drivers and creates a future which beco...
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
void OnNodeGuarding(::std::function< void(uint8_t, bool)> on_node_guarding)
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.
void OnEmcy(::std::function< void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy)
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.
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.
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.
void OnTime(::std::function< void(const ::std::chrono::system_clock::time_point &)> on_time)
void OnSync(::std::function< void(uint8_t, const time_point &)> on_sync)
The internal implementation of the CANopen master.
Sdo * GetSdo(uint8_t id)
Returns a pointer to the default client-SDO service for the given node.
void SetTimeout(const ::std::chrono::milliseconds &timeout)
Sets the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
void OnCanState(::std::function< void(io::CanState, io::CanState)> on_can_state)
@ NO_SDO
Resource not available: SDO connection.
int to_sdo_timeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
void SetTime()
Updates the CAN network time.
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
void Command(NmtCommand cs, uint8_t id=0)
Issues an NMT command to a slave.
void OnCanError(::std::function< void(io::CanError)> on_can_error)
SdoErrc sdo_errc(::std::error_code ec)
Returns the SDO abort code corresponding to an error code.
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.
#define CO_NMT_ST_START
The NMT state 'operational'.
virtual void OnCanError(io::CanError error) noexcept=0
The function invoked when an error is detected on the CAN bus.
void OnCanError(::std::function< void(io::CanError)> on_can_error)
__co_nmt * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt....
bool IsConfig(uint8_t id) const
Returns true if the remote node is configuring (i.e., the 'update configuration' step of the NMT 'boo...
virtual void OnCommand(NmtCommand cs) noexcept=0
The function invoked when an NMT state change occurs on the master.
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
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.
void OnSyncError(::std::function< void(uint16_t, uint8_t)> on_sync_error)
uint8_t subidx
The object sub-index.
@ ENTER_PREOP
Enter pre-operational.
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,...
void OnState(::std::function< void(uint8_t, NmtState)> on_state)
virtual void OnHeartbeat(bool occurred) noexcept=0
The function invoked when a heartbeat timeout event occurs or is resolved for the remote node.
void TpdoEvent(int num=0) noexcept