48 void OnCsInd(
CONMT* nmt, uint8_t cs) noexcept;
49 void OnHbInd(
CONMT* nmt, uint8_t
id,
int state,
int reason) noexcept;
50 void OnStInd(
CONMT* nmt, uint8_t
id, uint8_t st) noexcept;
52 void OnRpdoInd(
CORPDO* pdo, uint32_t ac,
const void* ptr,
size_t n) noexcept;
53 void OnRpdoErr(
CORPDO* pdo, uint16_t eec, uint8_t er) noexcept;
55 void OnTpdoInd(
COTPDO* pdo, uint32_t ac,
const void* ptr,
size_t n) noexcept;
57 void OnSyncInd(
CONMT* nmt, uint8_t cnt) noexcept;
58 void OnSyncErr(
COSync* sync, uint16_t eec, uint8_t er) noexcept;
60 void OnTimeInd(
COTime* time,
const timespec* tp) noexcept;
62 void OnEmcyInd(
COEmcy* emcy, uint8_t
id, uint16_t ec, uint8_t er,
63 uint8_t msef[5]) noexcept;
65 void OnRateInd(
COLSS*, uint16_t rate,
int delay) noexcept;
66 int OnStoreInd(
COLSS*, uint8_t
id, uint16_t rate) noexcept;
68 void RpdoRtr(
int num) noexcept;
78 ::std::function<void(uint8_t,
bool)> on_heartbeat;
79 ::std::function<void(uint8_t,
NmtState)> on_state;
80 ::std::function<void(
int, ::std::error_code,
const void*, ::std::size_t)>
82 ::std::function<void(
int, uint16_t, uint8_t)> on_rpdo_error;
83 ::std::function<void(
int, ::std::error_code,
const void*, ::std::size_t)>
85 ::std::function<void(uint8_t,
const time_point&)> on_sync;
86 ::std::function<void(uint16_t, uint8_t)> on_sync_error;
87 ::std::function<void(const ::std::chrono::system_clock::time_point&)> on_time;
88 ::std::function<void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy;
89 ::std::function<void(
int, ::std::chrono::milliseconds)> on_switch_bitrate;
93 const ::std::string& dcf_txt, const ::std::string& dcf_bin,
95 : io::CanNet(exec, timer, chan, 0, 0),
96 Device(dcf_txt, dcf_bin, id, this),
97 tpdo_event_mutex(*this),
103 Node::~Node() =
default;
122 wait.
value = util::to_timespec(t);
134 auto value = util::to_timespec(t);
136 if (!f) util::throw_errc(
"AsyncWait");
140 if (errc) util::throw_errc(
"AsyncWait", errc);
161 ::std::chrono::milliseconds delay) {
173 [
this, &ctrl, bitrate,
195 ::std::lock_guard<util::BasicLockable>
lock(*
this);
201 ::std::lock_guard<util::BasicLockable>
lock(*
this);
207 ::std::lock_guard<util::BasicLockable>
lock(*
this);
218 ::std::error_code& ec) {
219 ::std::lock_guard<util::BasicLockable>
lock(*
this);
231 ::std::error_code ec;
238 ::std::lock_guard<util::BasicLockable>
lock(*
this);
239 impl_->on_command = on_command;
244 ::std::lock_guard<util::BasicLockable>
lock(*
this);
245 impl_->on_heartbeat = on_heartbeat;
250 ::std::lock_guard<util::BasicLockable>
lock(*
this);
251 impl_->on_state = on_state;
256 ::std::function<
void(
int, ::std::error_code,
const void*, ::std::size_t)>
258 ::std::lock_guard<util::BasicLockable>
lock(*
this);
259 impl_->on_rpdo = on_rpdo;
264 ::std::lock_guard<util::BasicLockable>
lock(*
this);
265 impl_->on_rpdo_error = on_rpdo_error;
270 ::std::function<
void(
int, ::std::error_code,
const void*, ::std::size_t)>
272 ::std::lock_guard<util::BasicLockable>
lock(*
this);
273 impl_->on_tpdo = on_tpdo;
277 Node::OnSync(::std::function<
void(uint8_t,
const time_point&)> on_sync) {
278 ::std::lock_guard<util::BasicLockable>
lock(*
this);
279 impl_->on_sync = on_sync;
284 ::std::lock_guard<util::BasicLockable>
lock(*
this);
285 impl_->on_sync_error = on_sync_error;
290 ::std::function<
void(const ::std::chrono::system_clock::time_point&)>
292 ::std::lock_guard<util::BasicLockable>
lock(*
this);
293 impl_->on_time = on_time;
298 ::std::function<
void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy) {
299 ::std::lock_guard<util::BasicLockable>
lock(*
this);
300 impl_->on_emcy = on_emcy;
305 ::std::function<
void(
int, ::std::chrono::milliseconds)> on_switch_bitrate) {
306 ::std::lock_guard<util::BasicLockable>
lock(*
this);
307 impl_->on_switch_bitrate = on_switch_bitrate;
312 node->impl_->nmt->onTPDOEventLock();
317 node->impl_->nmt->onTPDOEventUnlock();
332 assert(new_state != old_state);
335 if (new_state == io::CanState::PASSIVE) {
338 }
else if (old_state == io::CanState::BUSOFF) {
346 return impl_->nmt.get();
350 Node::Error(uint16_t eec, uint8_t er,
const uint8_t msef[5]) noexcept {
351 impl_->nmt->onErr(eec, er, msef);
359 for (num = 1; num <= 512; num++) impl_->RpdoRtr(num);
365 impl_->nmt->onTPDOEvent(num);
371 if (impl_->on_can_state) {
372 auto f = impl_->on_can_state;
374 f(new_state, old_state);
381 if (impl_->on_can_error) {
382 auto f = impl_->on_can_error;
390 util::throw_error_code(
"OnStore", ::std::errc::operation_not_supported);
395 nmt->setCsInd<Impl_, &Impl_::OnCsInd>(
this);
396 nmt->setHbInd<Impl_, &Impl_::OnHbInd>(
this);
397 nmt->setStInd<Impl_, &Impl_::OnStInd>(
this);
399 nmt->setSyncInd<Impl_, &Impl_::OnSyncInd>(
this);
403 Node::Impl_::OnCsInd(
CONMT* nmt, uint8_t cs) noexcept {
405 auto lss = nmt->getLSS();
407 lss->setRateInd<Impl_, &Impl_::OnRateInd>(
this);
408 lss->setStoreInd<Impl_, &Impl_::OnStoreInd>(
this);
413 auto sync = nmt->getSync();
414 if (sync) sync->setErr<Impl_, &Impl_::OnSyncErr>(
this);
415 auto time = nmt->getTime();
416 if (time) time->setInd<Impl_, &Impl_::OnTimeInd>(
this);
417 auto emcy = nmt->getEmcy();
418 if (emcy) emcy->setInd<Impl_, &Impl_::OnEmcyInd>(
this);
422 for (
int i = 1; i <= 512; i++) {
423 auto pdo = nmt->getRPDO(i);
425 pdo->setInd<Impl_, &Impl_::OnRpdoInd>(
this);
426 pdo->setErr<Impl_, &Impl_::OnRpdoErr>(
this);
429 for (
int i = 1; i <= 512; i++) {
430 auto pdo = nmt->getTPDO(i);
431 if (pdo) pdo->setInd<Impl_, &Impl_::OnTpdoInd>(
this);
436 self->UpdateRpdoMapping();
437 self->UpdateTpdoMapping();
444 util::UnlockGuard<util::BasicLockable> unlock(*
self);
450 Node::Impl_::OnHbInd(CONMT* nmt, uint8_t
id,
int state,
int reason) noexcept {
452 nmt->onHb(
id, state, reason);
457 self->OnHeartbeat(
id, occurred);
460 auto f = on_heartbeat;
461 util::UnlockGuard<util::BasicLockable> unlock(*
self);
467 Node::Impl_::OnStInd(CONMT* nmt, uint8_t
id, uint8_t st) noexcept {
471 if (
id == nmt->getDev()->getId())
return;
473 self->OnState(
id,
static_cast<NmtState>(st));
477 util::UnlockGuard<util::BasicLockable> unlock(*
self);
483 Node::Impl_::OnRpdoInd(CORPDO* pdo, uint32_t ac,
const void* ptr,
485 int num = pdo->getNum();
486 self->OnRpdo(num,
static_cast<SdoErrc>(ac), ptr, n);
490 util::UnlockGuard<util::BasicLockable> unlock(*
self);
491 f(num,
static_cast<SdoErrc>(ac), ptr, n);
496 Node::Impl_::OnRpdoErr(CORPDO* pdo, uint16_t eec, uint8_t er) noexcept {
497 int num = pdo->getNum();
498 self->OnRpdoError(num, eec, er);
501 auto f = on_rpdo_error;
502 util::UnlockGuard<util::BasicLockable> unlock(*
self);
508 Node::Impl_::OnTpdoInd(COTPDO* pdo, uint32_t ac,
const void* ptr,
510 int num = pdo->getNum();
511 self->OnTpdo(num,
static_cast<SdoErrc>(ac), ptr, n);
515 util::UnlockGuard<util::BasicLockable> unlock(*
self);
516 f(num,
static_cast<SdoErrc>(ac), ptr, n);
521 Node::Impl_::OnSyncInd(CONMT*, uint8_t cnt) noexcept {
522 auto t =
self->GetClock().gettime();
523 self->OnSync(cnt, t);
527 util::UnlockGuard<util::BasicLockable> unlock(*
self);
533 Node::Impl_::OnSyncErr(COSync*, uint16_t eec, uint8_t er) noexcept {
534 self->OnSyncError(eec, er);
537 auto f = on_sync_error;
538 util::UnlockGuard<util::BasicLockable> unlock(*
self);
544 Node::Impl_::OnTimeInd(COTime*,
const timespec* tp) noexcept {
546 ::std::chrono::system_clock::time_point abs_time(util::from_timespec(*tp));
547 self->OnTime(abs_time);
551 util::UnlockGuard<util::BasicLockable> unlock(*
self);
557 Node::Impl_::OnEmcyInd(COEmcy*, uint8_t
id, uint16_t ec, uint8_t er,
558 uint8_t msef[5]) noexcept {
559 self->OnEmcy(
id, ec, er, msef);
563 util::UnlockGuard<util::BasicLockable> unlock(*
self);
569 Node::Impl_::OnRateInd(COLSS*, uint16_t rate,
int delay) noexcept {
570 self->OnSwitchBitrate(rate * 1000, ::std::chrono::milliseconds(delay));
572 if (on_switch_bitrate) {
573 auto f = on_switch_bitrate;
574 util::UnlockGuard<util::BasicLockable> unlock(*
self);
575 f(rate * 1000, ::std::chrono::milliseconds(delay));
580 Node::Impl_::OnStoreInd(COLSS*, uint8_t
id, uint16_t rate) noexcept {
582 self->OnStore(
id, rate * 1000);
590 Node::Impl_::RpdoRtr(
int num) noexcept {
591 auto pdo = nmt->getRPDO(num);
::std::unique_ptr< T, delete_c_type< T > > unique_c_ptr
A specialization of std::unique_ptr for trivial, standard layout or incomplete C types,...
unique_c_ptr< T > make_unique_c(Args &&... args)
Creates an instance of a trivial, standard layout or incomplete C type and wraps it in a lely::unique...
An opaque CAN network interface type.
An opaque CANopen device type.
An opaque CANopen EMCY producer/consumer service type.
An opaque CANopen LSS master/slave service type.
An opaque CANopen NMT master/slave service type.
An opaque CANopen Receive-PDO service type.
An opaque CANopen SYNC producer/consumer service type.
An opaque CANopen Transmit-PDO service type.
An opaque CANopen TIME producer/consumer service type.
The CANopen device description.
CODev * dev() const noexcept
Returns a pointer to the internal CANopen device from <lely/co/dev.hpp>.
uint8_t id() const noexcept
Returns the node-ID.
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
The base class for CANopen nodes.
ev::Future< void, ::std::exception_ptr > AsyncWait(ev_exec_t *exec, const time_point &t, io_tqueue_wait **pwait=nullptr)
Submits an asynchronous wait operation and creates a future which becomes ready once the wait operati...
void Reset()
(Re)starts the node.
void OnSyncError(::std::function< void(uint16_t, uint8_t)> on_sync_error)
Registers the function to be invoked when the data length of a received SYNC message does not match.
void OnSync(::std::function< void(uint8_t, const time_point &)> on_sync)
Registers the function to be invoked when a SYNC message is sent/received.
void OnState(::std::function< void(uint8_t, NmtState)> on_state)
Registers the function to be invoked whenan NMT state change or boot-up event is detected for a remot...
void ConfigHeartbeat(uint8_t id, const ::std::chrono::milliseconds &ms, ::std::error_code &ec)
Configures heartbeat consumption for the specified node by updating CANopen object 1016 (Consumer hea...
void SetTime()
Updates the CAN network time.
CANNet * net() const noexcept
Returns a pointer to the internal CAN network interface from <lely/can/net.hpp>.
void OnCanError(::std::function< void(io::CanError)> on_can_error)
Registers the function to be invoked when an error is detected on the CAN bus.
void OnCommand(::std::function< void(NmtCommand)> on_command)
Registers the function to be invoked when an NMT command is received from the master.
void OnSwitchBitrate(::std::function< void(int, ::std::chrono::milliseconds)> on_switch_bitrate)
Registers the function to be invoked when the LSS master activates the bit rate of all CANopen device...
void on_can_state(io::CanState new_state, io::CanState old_state) noexcept final
The function invoked when a CAN bus state change is detected.
Node(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 node.
CONMT * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt....
io::ContextBase GetContext() const noexcept
Returns the underlying I/O context with which this context is registered.
void TpdoEvent(int num=0) noexcept
Triggers the transmission of an acyclic or event-driven PDO.
void OnHeartbeat(::std::function< void(uint8_t, bool)> on_heartbeat)
Registers the function to be invoked when a heartbeat timeout event occurs or is resolved.
ev::Future< void, ::std::exception_ptr > AsyncSwitchBitrate(io::CanControllerBase &ctrl, int bitrate, ::std::chrono::milliseconds delay)
Stops the specified CAN controller and submits asynchronous operations to wait for the delay period,...
ev::Executor GetExecutor() const noexcept
Returns the executor used to process I/O and CANopen events.
void on_can_error(io::CanError error) noexcept final
The function invoked when an error is detected on the CAN bus.
void OnTime(::std::function< void(const ::std::chrono::system_clock::time_point &)> on_time)
Registers the function to be invoked when a TIME message is received.
void OnRpdo(::std::function< void(int, ::std::error_code, const void *, ::std::size_t)> on_rpdo)
Registers the function to be invoked when a Receive-PDO is processed.
void OnRpdoError(::std::function< void(int, uint16_t, uint8_t)> on_rpdo_error)
Registers the function to be invoked when a Receive-PDO length mismatch or timeout error occurs.
void OnTpdo(::std::function< void(int, ::std::error_code, const void *, ::std::size_t)> on_tpdo)
Registers the function to be invoked after a Transmit-PDO is sent or an error occurs.
io::Clock GetClock() const noexcept
Returns the clock used by the timer.
bool AbortWait(io_tqueue_wait &wait) noexcept
Aborts the specified wait operation if it is pending.
void OnEmcy(::std::function< void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy)
Registers the function to be invoked when an EMCY message is received.
void OnCanState(::std::function< void(io::CanState, io::CanState)> on_can_state)
Registers the function to be invoked when a CAN bus state change is detected.
void SubmitWait(const time_point &t, io_tqueue_wait &wait)
Submits a wait operation.
void RpdoRtr(int num=0) noexcept
Requests the transmission of a PDO by sending a CAN frame with the RTR (Remote Transmission Request) ...
virtual void OnStore(uint8_t id, int bitrate)
The function invoked then a request is received from the LSS master to store the pending node-ID and ...
bool CancelWait(io_tqueue_wait &wait) noexcept
Cancels the specified wait operation if it is pending.
The type of exception thrown when an SDO abort code is received.
The type of objects thrown as exceptions to report a system error with an associated error code.
An abstract task executor. This class is a wrapper around #ev_exec_t*.
result_type & get()
Returns the result of a ready future.
A reference to an abstract CAN channel.
A reference to an abstract CAN controller.
void stop(::std::error_code &ec) noexcept
void set_bitrate(int nominal, int data, ::std::error_code &ec) noexcept
void restart(::std::error_code &ec) noexcept
Clock get_clock() const noexcept
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process,...
void set_time()
Updates the CAN network time.
ev::Executor get_executor() const noexcept
ContextBase get_ctx() const noexcept
An abstract clock. This class is a wrapper around #io_clock_t*.
A refence to an I/O context. This class is a wrapper around #io_ctx_t*.
A reference to an abstract timer.
value_type & value()
Returns a reference to the value if *this contains a value, and throws an exception if *this contains...
A mutex wrapper that provides a convenient RAII-style mechanism for releasing a mutex for the duratio...
This header file is part of the CANopen library; it contains the C++ interface of the device descript...
This is the internal header file of the C++ CANopen application library.
This header file is part of the CANopen library; it contains the C++ interface of the emergency (EMCY...
CanError
The error flags of a CAN bus, which are not mutually exclusive.
CanState
The states of a CAN node, depending on the TX/RX error count.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
This header file is part of the CANopen library; it contains the C++ interface of the Layer Setting S...
SdoErrc
The SDO abort codes.
NmtCommand
The NMT command specifiers.
#define CO_NMT_CS_START
The NMT command specifier 'start'.
#define CO_NMT_CS_ENTER_PREOP
The NMT command specifier 'enter pre-operational'.
#define CO_NMT_CS_RESET_NODE
The NMT command specifier 'reset node'.
@ CO_NMT_EC_TIMEOUT
An NMT error control timeout event.
co_unsigned32_t co_dev_cfg_hb(co_dev_t *dev, co_unsigned8_t id, co_unsigned16_t ms)
Configures heartbeat consumption for the specified node by updating CANopen object 1016 (Consumer hea...
@ CO_NMT_EC_OCCURRED
An NMT error control event occurred.
#define CO_NMT_CS_RESET_COMM
The NMT command specifier 'reset communication'.
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 C++ CANopen application library; it contains the CANopen node declara...
This header file is part of the CANopen library; it contains the C++ interface of the Receive-PDO dec...
A wait operation suitable for use with a timer queue.
struct timespec value
The absolute expiration time.
The internal implementation of the CANopen node.
This header file is part of the CANopen library; it contains the C++ interface of the synchronization...
This header file is part of the CANopen library; it contains the C++ interface of the time stamp (TIM...
This header file is part of the CANopen library; it contains the C++ interface of the Transmit-PDO de...
size_t io_tqueue_abort_wait(io_tqueue_t *tq, struct io_tqueue_wait *wait)
Aborts the specified timer queue wait operation if it is pending.
size_t io_tqueue_cancel_wait(io_tqueue_t *tq, struct io_tqueue_wait *wait)
Cancels the specified timer queue wait operation if it is pending.
ev_future_t * io_tqueue_async_wait(io_tqueue_t *tq, ev_exec_t *exec, const struct timespec *value, struct io_tqueue_wait **pwait)
Submits an asynchronous wait operation to a timer queue and creates a future which becomes ready once...
void io_tqueue_submit_wait(io_tqueue_t *tq, struct io_tqueue_wait *wait)
Submits a wait operation to a timer queue.