Lely core libraries
2.2.5
|
Go to the documentation of this file.
26 #if !LELY_NO_COAPP_MASTER
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;
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;
64 ::std::lock_guard<util::BasicLockable>
lock(*node);
70 ::std::lock_guard<util::BasicLockable>
lock(*node);
76 const ::std::string& dcf_bin, uint8_t
id)
77 :
Node(exec, timer, chan, dcf_txt, dcf_bin,
id),
81 BasicMaster::~BasicMaster() =
default;
87 ::std::lock_guard<util::BasicLockable>
lock(*
this);
95 auto ready = impl_->ready[
id - 1];
96 impl_->ready[
id - 1] =
false;
98 impl_->ready[
id - 1] = ready;
99 util::throw_errc(
"Boot");
109 ::std::lock_guard<util::BasicLockable>
lock(
const_cast<BasicMaster&
>(*
this));
110 return impl_->ready[
id - 1];
116 ::std::lock_guard<util::BasicLockable>
lock(*
this);
118 if (it != end())
return impl_->AsyncDeconfig(it->second);
120 return ev::make_empty_future();
128 ::std::lock_guard<util::BasicLockable>
lock(*
this);
129 for (
const auto& it : *
this) futures[n++] = impl_->AsyncDeconfig(it.second);
133 ::std::array<ev_future_t*, CO_NUM_NODES> tmp;
134 ::std::copy_n(futures.begin(), n, tmp.begin());
140 ::std::lock_guard<util::BasicLockable>
lock(*
this);
142 if (
nmt()->nodeErrInd(
id) == -1) util::throw_errc(
"Error");
147 ::std::lock_guard<util::BasicLockable> lock(*
this);
149 Node::Error(eec, er, msef);
154 ::std::lock_guard<util::BasicLockable>
lock(*
this);
156 if (
nmt()->csReq(
static_cast<uint8_t
>(cs),
id) == -1)
157 util::throw_errc(
"Command");
162 ::std::lock_guard<util::BasicLockable> lock(*
this);
169 ::std::lock_guard<util::BasicLockable> lock(*
this);
174 ::std::chrono::milliseconds
176 ::std::lock_guard<util::BasicLockable>
lock(
const_cast<BasicMaster&
>(*
this));
183 ::std::lock_guard<util::BasicLockable>
lock(*
this);
190 ::std::lock_guard<util::BasicLockable>
lock(*
this);
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");
202 MapType::operator[](driver.
id()) = &driver;
207 ::std::lock_guard<util::BasicLockable>
lock(*
this);
209 auto id = driver.
id();
211 if (it != end() && it->second == &driver) {
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;
226 ::std::function<
void(uint8_t,
NmtState,
char, const ::std::string&)>
228 ::std::lock_guard<util::BasicLockable>
lock(*
this);
229 impl_->on_boot = on_boot;
234 if (
id &&
id <=
CO_NUM_NODES) impl_->ready[
id - 1] = ready;
239 for (
const auto& it : *
this) {
241 it.second->OnCanError(
error);
248 for (
const auto& it : *
this) {
250 it.second->OnCanState(new_state, old_state);
259 it->second->OnRpdoWrite(idx, subidx);
268 for (
const auto& it : *
this) {
270 it.second->OnCommand(cs);
279 it->second->OnNodeGuarding(occurred);
288 it->second->OnHeartbeat(occurred);
303 it->second->OnState(st);
309 const ::std::string& what) noexcept {
313 it->second->OnBoot(st, es, what);
323 ConfigResult(
id, ::std::error_code());
328 it->second->OnConfig([
this,
id](::std::error_code ec) {
329 ::std::lock_guard<util::BasicLockable> lock(*
this);
331 ConfigResult(
id, ec);
338 impl_->config[
id - 1] =
false;
339 if (nmt()->isBooting(
id))
341 impl_->sdos.erase(
id);
343 nmt()->cfgRes(
id,
static_cast<uint32_t
>(
sdo_errc(ec)));
348 for (
const auto& it : *
this) {
350 it.second->OnSync(cnt, t);
356 for (
const auto& it : *
this) {
358 it.second->OnSyncError(eec, er);
364 const ::std::chrono::system_clock::time_point& abs_time) noexcept {
365 for (
const auto& it : *
this) {
367 it.second->OnTime(abs_time);
373 uint8_t msef[5]) noexcept {
377 it->second->OnEmcy(eec, er, msef);
385 return impl_->config[
id - 1];
390 if (!
id ||
id > 0x7f)
391 throw ::std::out_of_range(
"invalid node-ID: " + ::std::to_string(
id));
394 auto st =
nmt()->getSt();
398 auto it = impl_->sdos.find(
id);
399 if (it != impl_->sdos.end())
return &it->second;
402 if (
nmt()->isBooting(
id))
return nullptr;
404 return &(impl_->sdos[
id] =
Sdo(
nmt()->getNet(),
id));
410 impl_->sdos.erase(
id);
417 for (
const auto& it : *
this) {
426 for (
const auto& it : *
this) {
429 [=]() { driver->
OnCanState(new_state, old_state); });
438 driver->
GetExecutor().
post([=]() { driver->OnRpdoWrite(idx, subidx); });
447 for (
const auto& it : *
this) {
488 const ::std::string& what) noexcept {
502 ConfigResult(
id, ::std::error_code());
509 driver->
OnConfig([
this,
id](::std::error_code ec) {
510 ::std::lock_guard<util::BasicLockable> lock(*
this);
511 ConfigResult(
id, ec);
518 for (
const auto& it : *
this) {
526 for (
const auto& it : *
this) {
534 const ::std::chrono::system_clock::time_point& abs_time) noexcept {
535 for (
const auto& it : *
this) {
543 uint8_t msef[5]) noexcept {
544 ::std::array<uint8_t, 5> value = {0};
545 ::std::copy_n(msef, value.size(), value.begin());
550 [=]()
mutable { driver->
OnEmcy(eec, er, value.data()); });
555 nmt->setNgInd<Impl_, &Impl_::OnNgInd>(
this);
556 nmt->setBootInd<Impl_, &Impl_::OnBootInd>(
this);
557 nmt->setCfgInd<Impl_, &Impl_::OnCfgInd>(
this);
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); });
571 BasicMaster::Impl_::OnNgInd(CONMT*
nmt, uint8_t
id,
int state,
572 int reason) noexcept {
574 nmt->onNg(
id, state, reason);
580 self->OnNodeGuarding(
id, occurred);
581 if (on_node_guarding) {
582 auto f = on_node_guarding;
583 util::UnlockGuard<util::BasicLockable>
unlock(*
self);
589 BasicMaster::Impl_::OnBootInd(CONMT*, uint8_t
id, uint8_t st,
591 if (
id &&
id <=
CO_NUM_NODES && (!es || es ==
'L')) ready[
id - 1] =
true;
593 self->OnBoot(
id,
static_cast<NmtState>(st), es, what);
596 util::UnlockGuard<util::BasicLockable>
unlock(*
self);
597 f(
id,
static_cast<NmtState>(st), es, what);
602 BasicMaster::Impl_::OnCfgInd(CONMT*, uint8_t
id, COCSDO* sdo) noexcept {
610 config[
id - 1] =
true;
618 #endif // !LELY_NO_COAPP_MASTER
void post(ev_task &task) noexcept
The abstract driver interface for a remote CANopen node.
An opaque CANopen Client-SDO service type.
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...
virtual void OnConfig(uint8_t id) noexcept
The function invoked when the 'update configuration' step is reached during the NMT 'boot slave' proc...
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(uint8_t id, uint16_t idx, uint8_t subidx) noexcept override
The default implementation queues a notification for the driver registered for node id.
void OnCanError(io::CanError error) noexcept override
The default implementation notifies all registered drivers.
::std::chrono::milliseconds GetTimeout() const
Returns the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
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...
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 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.
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 (...
Future< T, E > get_future() const noexcept
Returns a lely::ev::Future with (a reference to) the same shared state as *this.
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.
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.
#define CO_NMT_ST_PREOP
The NMT state 'pre-operational'.
An opaque CANopen NMT master/slave service type.
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 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 OnHeartbeat(uint8_t id, bool occurred) noexcept override
The default implementation queues a notification for the driver registered for node id.
void OnSync(uint8_t cnt, const time_point &t) noexcept override
The default implementation notifies all registered drivers.
CanError
The error flags of a CAN bus, which are not mutually exclusive.
void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept override
The default implementation notifies all registered drivers.
void OnCommand(NmtCommand cs) noexcept override
The default implementation notifies all registered drivers.
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 OnCommand(NmtCommand cs) noexcept override
The default implementation queues a notification for all registered drivers.
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.
void OnSyncError(uint16_t eec, uint8_t er) noexcept override
The default implementation queues a notification for all registered drivers.
const char * co_nmt_es2str(char es)
Returns a pointer to a string describing an NMT boot error status.
void OnRpdoWrite(uint8_t id, uint16_t idx, uint8_t subidx) noexcept override
The default implementation notifies the driver registered for node id.
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process,...
void OnState(uint8_t id, NmtState st) noexcept override
The default implementation notifies the driver registered for node id.
uint8_t id() const noexcept
Returns the node-ID.
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
void RpdoRtr(int num=0) noexcept
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.
void CancelSdo(uint8_t id=0)
Aborts any ongoing or pending SDO requests for the specified slave.
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.
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 OnState(uint8_t id, NmtState st) noexcept override
The default implementation queues a notification for the driver registered for node id.
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.
bool IsReady(uint8_t id) const
Returns true if the remote node is ready (i.e., the NMT 'boot slave' process has successfully complet...
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 OnHeartbeat(uint8_t id, bool occurred) noexcept override
The default implementation notifies the driver registered for node id.
void OnSyncError(uint16_t eec, uint8_t er) noexcept override
The default implementation notifies all registered drivers.
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.
The internal implementation of the CANopen master.
void OnSync(uint8_t cnt, const time_point &t) noexcept override
The default implementation queues a notification for all registered drivers.
void OnNodeGuarding(uint8_t id, bool occurred) noexcept override
The default implementation queues a notification for all registered drivers.
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.
int to_sdo_timeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
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.
SdoErrc sdo_errc(::std::error_code ec)
Returns the SDO abort code corresponding to an error code.
#define CO_NMT_ST_START
The NMT state 'operational'.
void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept override
The default implementation queues a notification for all registered drivers.
virtual void OnCanError(io::CanError error) noexcept=0
The function invoked when an error is detected on the CAN bus.
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...
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.
@ ENTER_PREOP
Enter pre-operational.
bool set(U &&u)
Satisfies a promise, if it was not aready satisfied, and stores the specified value as the result in ...
void OnCanError(io::CanError error) noexcept override
The default implementation queues a notification for all registered drivers.
CONMT * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt....
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 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.
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