26 #if !LELY_NO_COAPP_MASTER 47 void OnNgInd(
CONMT*
nmt, uint8_t
id,
int state,
int reason) noexcept;
48 void OnBootInd(
CONMT*
nmt, uint8_t
id, uint8_t st,
char es) noexcept;
52 ::std::map<uint8_t, Sdo> sdos;
56 const ::std::string& dcf_txt,
57 const ::std::string& dcf_bin, uint8_t
id)
58 :
Node(timer, bus, dcf_txt, dcf_bin, id),
61 BasicMaster::~BasicMaster() =
default;
65 ::std::lock_guard<BasicLockable>
lock(*
this);
67 if (
nmt()->nodeErrInd(
id) == -1) throw_errc(
"Error");
72 ::std::lock_guard<BasicLockable>
lock(*
this);
74 Node::Error(eec, er, msef);
79 ::std::lock_guard<BasicLockable>
lock(*
this);
86 ::std::lock_guard<BasicLockable>
lock(*
this);
91 ::std::chrono::milliseconds
93 ::std::lock_guard<BasicLockable>
lock(const_cast<BasicMaster&>(*
this));
100 ::std::lock_guard<BasicLockable>
lock(*
this);
107 ::std::lock_guard<BasicLockable>
lock(*
this);
109 if (!driver.
id() || driver.
id() > 0x7f)
110 throw ::std::out_of_range(
"invalid node-ID: " +
111 ::std::to_string(driver.
id()));
112 if (driver.
id() ==
nmt()->getDev()->getId())
113 throw ::std::out_of_range(
"cannot register node-ID of master: " +
114 ::std::to_string(driver.
id()));
115 if (find(driver.
id()) != end())
116 throw ::std::out_of_range(
"node-ID " + ::std::to_string(driver.
id()) +
117 " already registered");
119 MapType::operator[](driver.
id()) = &driver;
124 ::std::lock_guard<BasicLockable>
lock(*
this);
125 assert(find(driver.
id()) != end() && find(driver.
id())->second == &driver);
132 for (
const auto& it : *
this) {
134 it.second->OnCanError(
error);
140 for (
const auto& it : *
this) {
142 it.second->OnCanState(new_state, old_state);
151 for (
const auto& it : *
this) {
153 it.second->OnCommand(cs);
162 it->second->OnNodeGuarding(occurred);
171 it->second->OnHeartbeat(occurred);
183 it->second->OnState(st);
189 const ::std::string& what) noexcept {
193 it->second->OnBoot(st, es, what);
203 ConfigResult(
id, ::std::error_code());
208 it->second->OnConfig([=](::std::error_code ec) {
209 ::std::lock_guard<BasicLockable> lock(*
this);
211 ConfigResult(
id, ec);
217 assert(nmt()->isBooting(
id));
219 impl_->sdos.erase(
id);
221 nmt()->cfgRes(
id, ec.value());
226 ::std::size_t n) noexcept {
227 for (
const auto& it : *
this) {
229 it.second->OnRpdo(num, ec, p, n);
235 for (
const auto& it : *
this) {
237 it.second->OnRpdoError(num, eec, er);
243 ::std::size_t n) noexcept {
244 for (
const auto& it : *
this) {
246 it.second->OnTpdo(num, ec, p, n);
252 for (
const auto& it : *
this) {
254 it.second->OnSync(cnt, t);
260 for (
const auto& it : *
this) {
262 it.second->OnSyncError(eec, er);
268 const ::std::chrono::system_clock::time_point& abs_time) noexcept {
269 for (
const auto& it : *
this) {
271 it.second->OnTime(abs_time);
277 uint8_t msef[5]) noexcept {
281 it->second->OnEmcy(eec, er, msef);
287 if (!
id ||
id > 0x7f)
288 throw ::std::out_of_range(
"invalid node-ID: " + ::std::to_string(
id));
291 auto st =
nmt()->getSt();
295 auto it = impl_->sdos.find(
id);
296 if (it != impl_->sdos.end())
return &it->second;
299 if (
nmt()->isBooting(
id))
return nullptr;
301 return &(impl_->sdos[
id] =
Sdo(
nmt()->getNet(),
id));
307 impl_->sdos.erase(
id);
314 for (
const auto& it : *
this) {
316 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
325 for (
const auto& it : *
this) {
327 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
328 if (!ec) driver->
OnCanState(new_state, old_state);
339 for (
const auto& it : *
this) {
341 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
353 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
365 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
380 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
389 const ::std::string& what) noexcept {
393 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
394 if (!ec) driver->
OnBoot(st, es, what);
406 ConfigResult(
id, ::std::error_code());
412 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
414 driver->
OnConfig([=](::std::error_code ec) {
415 ::std::lock_guard<BasicLockable> lock(*
this);
416 ConfigResult(
id, ec);
419 ::std::lock_guard<BasicLockable> lock(*
this);
428 ::std::size_t n) noexcept {
429 ::std::array<uint8_t, CAN_MAX_LEN> value;
430 ::std::copy_n(static_cast<const uint8_t*>(p), ::std::min(n, value.size()),
432 for (
const auto& it : *
this) {
435 auto op =
new aio::TaskWrapper([=](::std::error_code ec_) {
436 if (!ec_) driver->
OnRpdo(num, ec, value.data(), value.size());
444 for (
const auto& it : *
this) {
446 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
455 ::std::size_t n) noexcept {
456 ::std::array<uint8_t, CAN_MAX_LEN> value;
457 ::std::copy_n(static_cast<const uint8_t*>(p), ::std::min(n, value.size()),
459 for (
const auto& it : *
this) {
461 auto op =
new aio::TaskWrapper([=](::std::error_code ec_) {
462 if (!ec_) driver->
OnTpdo(num, ec, value.data(), value.size());
470 for (
const auto& it : *
this) {
472 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
473 if (!ec) driver->
OnSync(cnt, t);
481 for (
const auto& it : *
this) {
483 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
492 const ::std::chrono::system_clock::time_point& abs_time) noexcept {
493 for (
const auto& it : *
this) {
495 auto op =
new aio::TaskWrapper([=](::std::error_code ec) {
496 if (!ec) driver->
OnTime(abs_time);
504 uint8_t msef[5]) noexcept {
505 ::std::array<uint8_t, 5> value = {0};
506 ::std::copy_n(msef, value.size(), value.begin());
510 auto op =
new aio::TaskWrapper([=](::std::error_code ec)
mutable {
511 if (!ec) driver->
OnEmcy(eec, er, value.data());
518 nmt->setNgInd<Impl_, &Impl_::OnNgInd>(
this);
519 nmt->setBootInd<Impl_, &Impl_::OnBootInd>(
this);
520 nmt->setCfgInd<Impl_, &Impl_::OnCfgInd>(
this);
524 BasicMaster::Impl_::OnNgInd(
CONMT* nmt, uint8_t
id,
int state,
525 int reason) noexcept {
527 nmt->onNg(
id, state, reason);
536 BasicMaster::Impl_::OnBootInd(CONMT*, uint8_t
id, uint8_t st,
538 self->OnBoot(
id, static_cast<NmtState>(st), es, es ?
co_nmt_es2str(es) :
"");
542 BasicMaster::Impl_::OnCfgInd(CONMT*, uint8_t
id, COCSDO* sdo) noexcept {
557 #endif // !LELY_NO_COAPP_MASTER 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 OnConfig(uint8_t id) noexcept
The function invoked when the 'update configuration' step is reached during the NMT 'boot slave' proc...
void OnSyncError(uint16_t eec, uint8_t er) noexcept override
The default implementation notifies all registered drivers.
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.
#define CO_NMT_ST_START
The NMT state 'operational'.
void CancelSdo(uint8_t id=0)
Aborts any ongoing or pending SDO requests for the specified slave.
void OnCanError(CanError error) noexcept override
The default implementation queues a notification for all registered drivers.
void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept override
The default implementation queues a notification for all registered drivers.
void OnState(uint8_t id, NmtState st) noexcept override
The default implementation notifies the driver registered for node id.
An NMT error control event occurred.
void OnRpdoError(int num, uint16_t eec, uint8_t er) noexcept override
The default implementation queues a notification for all registered drivers.
NmtCommand
The NMT command specifiers.
virtual void OnNodeGuarding(bool occurred) noexcept=0
The function invoked when a node guarding timeout event occurs or is resolved for the remote node...
const char * co_nmt_es2str(char es)
Returns a pointer to a string describing an NMT boot error status.
virtual uint8_t id() const noexcept=0
Returns the node-ID.
CONMT * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt.hpp>.
The abstract driver interface for a remote CANopen node.
void SetTimeout(const ::std::chrono::milliseconds &timeout)
Sets the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
An opaque CANopen Client-SDO service type.
void OnTpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept override
The default implementation notifies all registered drivers.
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 OnSync(uint8_t cnt, const time_point &t) noexcept override
The default implementation notifies all registered drivers.
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.
void Error(uint8_t id)
Indicates the occurrence of an error event on a remote node and triggers the error handling process (...
virtual void OnCommand(NmtCommand cs) noexcept=0
The function invoked when an NMT state change occurs on the master.
void OnHeartbeat(uint8_t id, bool occurred) noexcept override
The default implementation queues a notification for the driver registered for node id...
virtual void OnRpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept=0
The function invoked when a Receive-PDO is processed by the master.
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 OnCanState(CanState new_state, CanState old_state) noexcept=0
The function invoked when a CAN bus state change is detected.
virtual void OnTpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept=0
The function invoked after a Transmit-PDO is sent by the master or an error occurs.
This header file is part of the CANopen library; it contains the C++ interface of the network managem...
This header file is part of the CANopen library; it contains the C++ interface of the device descript...
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...
virtual void OnBoot(uint8_t id, NmtState st, char es, const ::std::string &what) noexcept
The function invoked when the NMT 'boot slave' process completes.
void OnSync(uint8_t cnt, const time_point &t) noexcept override
The default implementation queues a notification for all registered drivers.
The internal implementation of the CANopen master.
void OnNodeGuarding(uint8_t id, bool occurred) noexcept override
The default implementation queues a notification for all registered drivers.
#define CO_NMT_ST_PREOP
The NMT state 'pre-operational'.
virtual void OnNodeGuarding(uint8_t id, bool occurred) noexcept
The function invoked when a node guarding timeout event occurs or is resolved.
inline ::std::chrono::milliseconds FromTimeout(int timeout)
Converts an SDO timeout to a duration.
void OnCommand(NmtCommand cs) noexcept override
The default implementation notifies all registered drivers.
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 RpdoRtr(int num=0)
Requests the transmission of a PDO.
The type of objects thrown as exceptions to report a system error with an associated error code...
This header file is part of the C++ CANopen application library; it contains the remote node driver i...
void OnCanState(CanState new_state, CanState old_state) noexcept override
The default implementation invokes lely::canopen::Node::OnCanState() and notifies each registered dri...
void OnCanError(CanError error) noexcept override
The default implementation notifies all registered drivers.
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...
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.
virtual void OnRpdoError(int num, uint16_t eec, uint8_t er) noexcept=0
The function invoked when a Receive-PDO length mismatch or timeout error occurs on the master...
void OnState(uint8_t id, NmtState st) noexcept override
The default implementation queues a notification for the driver registered for node id...
This header file is part of the C++ CANopen application library; it contains the timeout conversion f...
void TpdoEvent(int num=0)
Triggers the transmission of an event-driven (asynchronous) PDO.
virtual void OnCanError(CanError error) noexcept=0
The function invoked when an error is detected on the CAN bus.
virtual void OnHeartbeat(bool occurred) noexcept=0
The function invoked when a heartbeat timeout event occurs or is resolved for the remote node...
int ToTimeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
An NMT error control timeout event.
This is the internal header file of the C++ CANopen application library.
void OnCommand(NmtCommand cs) noexcept override
The default implementation queues a notification for all registered drivers.
void Insert(DriverBase &driver)
Registers a driver for a remote CANopen node.
void OnSyncError(uint16_t eec, uint8_t er) noexcept override
The default implementation queues a notification for all registered drivers.
virtual aio::ExecutorBase GetExecutor() const noexcept=0
Returns the executor used to execute event handlers for this driver, including SDO confirmation funct...
void RpdoRtr(int num=0)
Requests the transmission of a PDO.
virtual void OnSync(uint8_t cnt, const Node::time_point &t) noexcept=0
The function invoked when a SYNC message is sent/received by the master.
void OnConfig(uint8_t id) noexcept override
The default implementation queues a notification for the driver registered for node id...
void OnHeartbeat(uint8_t id, bool occurred) noexcept override
The default implementation notifies the driver registered for node id.
::std::chrono::milliseconds GetTimeout() const
Returns the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes...
An opaque CANopen NMT master/slave service type.
void OnCanState(CanState new_state, CanState old_state) noexcept override
The default implementation invokes lely::canopen::Node::OnCanState() and queues a notification for ea...
BasicMaster(aio::TimerBase &timer, aio::CanBusBase &bus, const ::std::string &dcf_txt, const ::std::string &dcf_bin="", uint8_t id=0xff)
Creates a new CANopen master.
A mutex wrapper that provides a convenient RAII-style mechanism for releasing a mutex for the duratio...
void OnRpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept override
The default implementation queues a notification for all registered drivers.
virtual void lock() final override
Blocks until a lock can be obtained for the current execution agent (thread, process, task).
Global namespace for the Lely Industries N.V. libraries.
uint8_t id() const noexcept
Returns the node-ID.
void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept override
The default implementation notifies all registered drivers.
void ConfigResult(uint8_t id, ::std::error_code ec) noexcept
Reports the result of the 'update configuration' step to the NMT service.
Sdo * GetSdo(uint8_t id)
Returns a pointer to the default client-SDO service for the given node.
The base class for CANopen nodes.
void OnRpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept override
The default implementation notifies all registered drivers.
void OnTpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept override
The default implementation queues a notification for all registered drivers.
void OnRpdoError(int num, uint16_t eec, uint8_t er) noexcept override
The default implementation notifies all registered drivers.
void Erase(DriverBase &driver)
Unregisters a driver for a remote CANopen node.
void TpdoEvent(int num=0)
Triggers the transmission of an event-driven (asynchronous) PDO.