25 #include <lely/aio/detail/timespec.hpp> 32 #if !LELY_NO_THREADS && defined(__MINGW32__) 57 virtual void lock()
override;
58 virtual void unlock()
override;
60 void OnCsInd(
CONMT* nmt, uint8_t cs) noexcept;
61 void OnHbInd(
CONMT* nmt, uint8_t
id,
int state,
int reason) noexcept;
62 void OnStInd(
CONMT* nmt, uint8_t
id, uint8_t st) noexcept;
64 void OnRpdoInd(
CORPDO* pdo, uint32_t ac,
const void* ptr,
size_t n) noexcept;
65 void OnRpdoErr(
CORPDO* pdo, uint16_t eec, uint8_t er) noexcept;
67 void OnTpdoInd(
COTPDO* pdo, uint32_t ac,
const void* ptr,
size_t n) noexcept;
69 void OnSyncInd(
CONMT* nmt, uint8_t cnt) noexcept;
70 void OnSyncErr(
COSync* sync, uint16_t eec, uint8_t er) noexcept;
72 void OnTimeInd(
COTime* time,
const timespec* tp) noexcept;
74 void OnEmcyInd(
COEmcy* emcy, uint8_t
id, uint16_t ec, uint8_t er,
75 uint8_t msef[5]) noexcept;
77 void RpdoRtr(
int num);
78 void TpdoEvent(
int num);
94 const ::std::string& dcf_txt, const ::std::string& dcf_bin,
97 Device(dcf_txt, dcf_bin, id, this),
100 Node::~Node() =
default;
104 ::std::lock_guard<Impl_>
lock(*impl_);
124 assert(new_state != old_state);
127 if (new_state == CanState::PASSIVE) {
130 }
else if (old_state == CanState::BUSOFF) {
138 return impl_->nmt.get();
142 Node::Error(uint16_t eec, uint8_t er,
const uint8_t msef[5]) {
143 impl_->nmt->onErr(eec, er, msef);
151 for (num = 1; num <= 512; num++) impl_->RpdoRtr(num);
158 impl_->TpdoEvent(num);
160 for (num = 1; num <= 512; num++) impl_->TpdoEvent(num);
172 nmt->setCsInd<Impl_, &Impl_::OnCsInd>(
this);
173 nmt->setHbInd<Impl_, &Impl_::OnHbInd>(
this);
174 nmt->setStInd<Impl_, &Impl_::OnStInd>(
this);
176 nmt->setSyncInd<Impl_, &Impl_::OnSyncInd>(
this);
181 Node::Impl_::~Impl_() {
214 Node::Impl_::OnCsInd(
CONMT*
nmt, uint8_t cs) noexcept {
216 auto sync =
nmt->getSync();
217 if (sync) sync->setErr<
Impl_, &Impl_::OnSyncErr>(
this);
218 auto time =
nmt->getTime();
219 if (time) time->setInd<
Impl_, &Impl_::OnTimeInd>(
this);
220 auto emcy =
nmt->getEmcy();
221 if (emcy) emcy->setInd<
Impl_, &Impl_::OnEmcyInd>(
this);
225 for (
int i = 1; i <= 512; i++) {
226 auto pdo =
nmt->getRPDO(i);
228 pdo->setInd<Impl_, &Impl_::OnRpdoInd>(
this);
229 pdo->setErr<Impl_, &Impl_::OnRpdoErr>(
this);
232 for (
int i = 1; i <= 512; i++) {
233 auto pdo =
nmt->getTPDO(i);
234 if (pdo) pdo->setInd<Impl_, &Impl_::OnTpdoInd>(
this);
238 self->OnCommand(static_cast<NmtCommand>(cs));
242 Node::Impl_::OnHbInd(CONMT*
nmt, uint8_t
id,
int state,
int reason) noexcept {
244 nmt->onHb(
id, state, reason);
252 Node::Impl_::OnStInd(CONMT*
nmt, uint8_t
id, uint8_t st) noexcept {
256 if (
id ==
nmt->getDev()->getId())
return;
258 self->OnState(
id, static_cast<NmtState>(st));
262 Node::Impl_::OnRpdoInd(CORPDO* pdo, uint32_t ac,
const void* ptr,
264 int num = pdo->getNum();
265 self->OnRpdo(num, static_cast<SdoErrc>(ac), ptr, n);
269 Node::Impl_::OnRpdoErr(CORPDO* pdo, uint16_t eec, uint8_t er) noexcept {
270 self->OnRpdoError(pdo->getNum(), eec, er);
274 Node::Impl_::OnTpdoInd(COTPDO* pdo, uint32_t ac,
const void* ptr,
276 self->OnTpdo(pdo->getNum(),
static_cast<SdoErrc>(ac), ptr, n);
280 Node::Impl_::OnSyncInd(CONMT*, uint8_t cnt) noexcept {
281 self->OnSync(cnt, Node::time_point::clock::now());
285 Node::Impl_::OnSyncErr(COSync*, uint16_t eec, uint8_t er) noexcept {
286 self->OnSyncError(eec, er);
290 Node::Impl_::OnTimeInd(COTime*,
const timespec* tp) noexcept {
292 ::std::chrono::system_clock::time_point abs_time(
293 aio::detail::FromTimespec(*tp));
294 self->OnTime(abs_time);
298 Node::Impl_::OnEmcyInd(COEmcy*, uint8_t
id, uint16_t ec, uint8_t er,
299 uint8_t msef[5]) noexcept {
300 self->OnEmcy(
id, ec, er, msef);
304 Node::Impl_::RpdoRtr(
int num) {
305 auto pdo =
nmt->getRPDO(num);
306 if (pdo && pdo->rtr() == -1) throw_errc(
"RpdoRtr");
310 Node::Impl_::TpdoEvent(
int num) {
311 auto pdo =
nmt->getTPDO(num);
312 if (pdo && pdo->event() == -1) throw_errc(
"TpdoEvent");
An NMT error control event occurred.
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...
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
virtual void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
CONMT * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt.hpp>.
virtual void unlock() final override
Releases the lock held by the execution agent. Throws no exceptions.
An opaque CANopen device type.
Indicates that the requested operation succeeded.
A mutex type that supports neither timeout nor test and return.
void OnCanState(CanState new_state, CanState old_state) noexcept override
Implements the default behavior for a CAN bus state change.
Node(aio::TimerBase &timer, aio::CanBusBase &bus, const ::std::string &dcf_txt, const ::std::string &dcf_bin="", uint8_t id=0xff)
Creates a new CANopen node.
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
CANNet * net() const noexcept
Returns a pointer to the internal CAN network interface from <lely/can/net.hpp>.
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...
This header file is part of the C11 and POSIX compatibility library; it includes <threads.h>, if it exists, and defines any missing functionality.
void SetTime()
Update the CAN network time.
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
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...
This header file is part of the CANopen library; it contains the C++ interface of the time stamp (TIM...
#define CO_NMT_CS_RESET_NODE
The NMT command specifier 'reset node'.
SdoErrc
The SDO abort codes.
#define CO_NMT_CS_ENTER_PREOP
The NMT command specifier 'enter pre-operational'.
An opaque CANopen Receive-PDO service type.
virtual void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process, task).
An abstract interface conforming to the BasicLockable concept.
This header file is part of the CANopen library; it contains the C++ interface of the emergency (EMCY...
An NMT error control timeout event.
This is the internal header file of the C++ CANopen application library.
An opaque CANopen Transmit-PDO service type.
void Reset()
(Re)starts the node.
::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.
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...
void RpdoRtr(int num=0)
Requests the transmission of a PDO.
This header file is part of the C++ CANopen application library; it contains the CANopen node declara...
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>.
virtual void lock() final override
Blocks until a lock can be obtained for the current execution agent (thread, process, task).
The CANopen device description.
#define CO_NMT_CS_START
The NMT command specifier 'start'.
Global namespace for the Lely Industries N.V. libraries.
An opaque CAN network interface type.
An opaque CANopen SYNC producer/consumer service type.
The base class for CANopen nodes.
An opaque CANopen TIME producer/consumer service type.
The internal implementation of the CANopen node.
int mtx_init(mtx_t *mtx, int type)
Creates a mutex object with properties indicated by type, which must have one of the four values: ...
void TpdoEvent(int num=0)
Triggers the transmission of an event-driven (asynchronous) PDO.