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;
72 ::std::function<void(io::CanState, io::CanState)> on_can_state;
73 ::std::function<void(io::CanError)> on_can_error;
77 ::std::function<void(NmtCommand)> on_command;
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),
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");
139 int errc = f.
get().error();
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);
394 :
self(self_),
nmt(make_unique_c<CONMT>(net, dev)) {
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();
440 self->OnCommand(static_cast<NmtCommand>(cs));
445 f(static_cast<NmtCommand>(cs));
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;
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));
478 f(
id, static_cast<NmtState>(st));
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);
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;
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);
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);
533 Node::Impl_::OnSyncErr(
COSync*, uint16_t eec, uint8_t er) noexcept {
534 self->OnSyncError(eec, er);
537 auto f = on_sync_error;
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);
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);
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;
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);
An NMT error control timeout event.
void set_bitrate(int nominal, int data, ::std::error_code &ec) noexcept
A reference to an abstract timer.
TpdoEventMutex tpdo_event_mutex
The mutex used to postpone the transmission of acyclic and event-driven PDOs.
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.
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...
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
CanNet(ev_exec_t *exec, io_timer_t *timer, io_can_chan_t *chan, ::std::size_t txlen=0, int txtimeo=0)
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.
void lock() final
Blocks until a lock can be obtained for the current execution agent (thread, process, task).
io::Clock GetClock() const noexcept
Returns the clock used by the timer.
void stop(::std::error_code &ec) noexcept
struct timespec value
The absolute expiration time.
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...
A refence to an I/O context. This class is a wrapper around io_ctx_t*.
This is the internal header file of the C++ CANopen application library.
void SubmitWait(const time_point &t, io_tqueue_wait &wait)
Submits a wait operation.
NmtCommand
The NMT command specifiers.
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...
io::ContextBase GetContext() const noexcept
Returns the underlying I/O context with which this context is registered.
void unlock() final
Releases the lock held by the execution agent. Throws no exceptions.
A wait operation suitable for use with a timer queue.
CONMT * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt.hpp>.
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...
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 ...
void on_can_error(io::CanError error) noexcept final
The function invoked when an error is detected on the CAN bus.
An NMT error control event occurred.
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.
CanState
The states of a CAN node, depending on the TX/RX error count.
ev::Executor GetExecutor() const noexcept
Returns the executor used to process I/O and CANopen events.
An opaque CANopen device type.
An opaque CANopen LSS master/slave service type.
bool AbortWait(io_tqueue_wait &wait) noexcept
Aborts the specified wait operation if it is pending.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
This header file is part of the CANopen library; it contains the C++ interface of the network managem...
void restart(::std::error_code &ec) noexcept
ContextBase get_ctx() const noexcept
Clock get_clock() const noexcept
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 on_can_state(io::CanState new_state, io::CanState old_state) noexcept final
The function invoked when a CAN bus state change is detected.
An opaque CANopen EMCY producer/consumer service type.
This header file is part of the CANopen library; it contains the C++ interface of the synchronization...
CanError
The error flags of a CAN bus, which are not mutually exclusive.
void SetTime()
Updates the CAN network time.
This header file is part of the CANopen library; it contains the C++ interface of the time stamp (TIM...
A mutex wrapper that provides a convenient RAII-style mechanism for releasing a mutex for the duratio...
void set_time()
Updates the CAN network time.
#define CO_NMT_CS_RESET_NODE
The NMT command specifier 'reset node'.
SdoErrc
The SDO abort codes.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
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...
#define CO_NMT_CS_ENTER_PREOP
The NMT command specifier 'enter pre-operational'.
An opaque CANopen Receive-PDO service type.
The type of objects thrown as exceptions to report a system error with an associated error code...
void OnCommand(::std::function< void(NmtCommand)> on_command)
Registers the function to be invoked when an NMT command is received from the master.
void io_tqueue_submit_wait(io_tqueue_t *tq, struct io_tqueue_wait *wait)
Submits a wait operation to a timer queue.
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...
An abstract clock. This class is a wrapper around io_clock_t*.
This header file is part of the CANopen library; it contains the C++ interface of the emergency (EMCY...
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 OnSync(::std::function< void(uint8_t, const time_point &)> on_sync)
Registers the function to be invoked when a SYNC message is sent/received.
CANNet * net() const noexcept
Returns a pointer to the internal CAN network interface from <lely/can/net.hpp>.
An opaque CANopen Transmit-PDO service type.
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 Reset()
(Re)starts the node.
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.
An abstract task executor. This class is a wrapper around ev_exec_t*.
void RpdoRtr(int num=0) noexcept
Requests the transmission of a PDO by sending a CAN frame with the RTR (Remote Transmission Request) ...
This header file is part of the CANopen library; it contains the C++ interface of the Receive-PDO dec...
This header file is part of the CANopen library; it contains the C++ interface of the Transmit-PDO de...
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.
result_type & get()
Returns the result of a ready future.
This header file is part of the C++ CANopen application library; it contains the CANopen node declara...
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.
void TpdoEvent(int num=0) noexcept
Triggers the transmission of an acyclic or event-driven PDO.
ev::Executor get_executor() const noexcept
This header file is part of the CANopen library; it contains the C++ interface of the Layer Setting S...
An opaque CANopen NMT master/slave service type.
CODev * dev() const noexcept
Returns a pointer to the internal CANopen device from <lely/co/dev.hpp>.
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
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...
The CANopen device description.
A reference to an abstract CAN controller.
#define CO_NMT_CS_START
The NMT command specifier 'start'.
::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, using lely::delete_c_type as the deleter.
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 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.
An opaque CAN network interface type.
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.
uint8_t id() const noexcept
Returns the node-ID.
An opaque CANopen SYNC producer/consumer service type.
The base class for CANopen nodes.
#define CO_NMT_CS_RESET_COMM
The NMT command specifier 'reset communication'.
bool CancelWait(io_tqueue_wait &wait) noexcept
Cancels the specified wait operation if it is pending.
An opaque CANopen TIME producer/consumer service type.
The type of exception thrown when an SDO abort code is received.
This header file is part of the CANopen library; it contains the C++ interface of the device descript...
A reference to an abstract CAN channel.
The internal implementation of the CANopen node.
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process, task).