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),
61BasicMaster::~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
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);
524BasicMaster::Impl_::OnNgInd(
CONMT* nmt, uint8_t
id,
int state,
525 int reason)
noexcept {
527 nmt->onNg(
id, state, reason);
536BasicMaster::Impl_::OnBootInd(CONMT*, uint8_t
id, uint8_t st,
542BasicMaster::Impl_::OnCfgInd(CONMT*, uint8_t
id, COCSDO* sdo)
noexcept {
This header file is part of the C++ CANopen application library; it contains the timeout conversion f...
An opaque CANopen Client-SDO service type.
An opaque CANopen NMT master/slave service type.
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.
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.
void OnConfig(uint8_t id) noexcept override
The default implementation queues a notification for the driver registered for node id.
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 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 OnNodeGuarding(uint8_t id, bool occurred) noexcept override
The default implementation queues a notification for all registered drivers.
void OnSync(uint8_t cnt, const time_point &t) 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 queues a notification for all registered drivers.
void OnHeartbeat(uint8_t id, bool occurred) noexcept override
The default implementation queues a notification for the driver registered for node id.
void OnSyncError(uint16_t eec, uint8_t er) noexcept override
The default implementation queues a notification for all registered drivers.
void OnCanState(CanState new_state, CanState old_state) noexcept override
The default implementation invokes lely::canopen::Node::OnCanState() and queues a notification for ea...
void OnCommand(NmtCommand cs) noexcept override
The default implementation queues a notification for all registered drivers.
void OnState(uint8_t id, NmtState st) noexcept override
The default implementation queues a notification for the driver registered for node id.
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 OnSyncError(uint16_t eec, uint8_t er) noexcept override
The default implementation notifies all registered drivers.
void RpdoRtr(int num=0)
Requests the transmission of a PDO.
virtual void OnConfig(uint8_t id) noexcept
The function invoked when the 'update configuration' step is reached during the NMT 'boot slave' proc...
void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept override
The default implementation notifies all registered drivers.
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 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.
void OnHeartbeat(uint8_t id, bool occurred) noexcept override
The default implementation notifies the driver registered for node id.
void Erase(DriverBase &driver)
Unregisters a driver for a remote CANopen node.
void OnSync(uint8_t cnt, const time_point &t) noexcept override
The default implementation notifies all registered drivers.
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.
void TpdoEvent(int num=0)
Triggers the transmission of an event-driven (asynchronous) PDO.
void Insert(DriverBase &driver)
Registers a driver for a remote CANopen node.
void OnRpdoError(int num, uint16_t eec, uint8_t er) noexcept override
The default implementation notifies all registered drivers.
void Error(uint8_t id)
Indicates the occurrence of an error event on a remote node and triggers the error handling process (...
void OnCanError(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 OnState(uint8_t id, NmtState st) noexcept override
The default implementation notifies the driver registered for node id.
void OnCommand(NmtCommand cs) noexcept override
The default implementation notifies all registered drivers.
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 OnTpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept override
The default implementation notifies all registered drivers.
void SetTimeout(const ::std::chrono::milliseconds &timeout)
Sets the SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
void ConfigResult(uint8_t id, ::std::error_code ec) noexcept
Reports the result of the 'update configuration' step to the NMT service.
void CancelSdo(uint8_t id=0)
Aborts any ongoing or pending SDO requests for the specified slave.
void OnCanState(CanState new_state, CanState old_state) noexcept override
The default implementation invokes lely::canopen::Node::OnCanState() and notifies each registered dri...
virtual void OnNodeGuarding(uint8_t id, bool occurred) noexcept
The function invoked when a node guarding timeout event occurs or is resolved.
Sdo * GetSdo(uint8_t id)
Returns a pointer to the default client-SDO service for the given node.
uint8_t id() const noexcept
Returns the node-ID.
The abstract driver interface for a remote CANopen node.
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.
virtual void OnCommand(NmtCommand cs) noexcept=0
The function invoked when an NMT state change occurs on 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 OnSync(uint8_t cnt, const Node::time_point &t) noexcept=0
The function invoked when a SYNC message is sent/received by the master.
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 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.
virtual void OnCanError(CanError error) noexcept=0
The function invoked when an error is detected on the CAN bus.
virtual aio::ExecutorBase 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 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.
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.
virtual void OnCanState(CanState new_state, CanState old_state) noexcept=0
The function invoked when a CAN bus state change is detected.
The base class for CANopen nodes.
void TpdoEvent(int num=0)
Triggers the transmission of an event-driven (asynchronous) PDO.
CONMT * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt....
void RpdoRtr(int num=0)
Requests the transmission of a PDO.
virtual void lock() final override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
A mutex wrapper that provides a convenient RAII-style mechanism for releasing a mutex for the duratio...
The type of objects thrown as exceptions to report a system error with an associated error code.
This header file is part of the CANopen library; it contains the C++ interface of the device descript...
This header file is part of the C++ CANopen application library; it contains the remote node driver i...
inline ::std::chrono::milliseconds FromTimeout(int timeout)
Converts an SDO timeout to a duration.
int ToTimeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
NmtCommand
The NMT command specifiers.
@ ENTER_PREOP
Enter pre-operational.
Global namespace for the Lely Industries N.V. libraries.
@ CO_NMT_EC_OCCURRED
An NMT error control event occurred.
const char * co_nmt_es2str(char es)
Returns a pointer to a string describing an NMT boot error status.
#define CO_NMT_ST_PREOP
The NMT state 'pre-operational'.
#define CO_NMT_ST_START
The NMT state 'operational'.
@ CO_NMT_EC_TIMEOUT
An NMT error control timeout event.
This header file is part of the CANopen library; it contains the C++ interface of the network managem...
This is the internal header file of the C++ CANopen application library.
The internal implementation of the CANopen master.