1 CANopen library overview
2 ========================
4 Contrary to most other CANopen stacks, this implementation is completely
5 passive; the library does not perform any I/O (besides may reading some files
6 from disk), it does not create threads nor does it access the system clock.
7 Instead, it relies on the user to send and receive CAN frames and update the
8 clock. This allows the library to be easily embedded in a wide variety of
11 The library is also asynchronous. Issuing a request is always a non-blocking
12 operation. If the request is confirmed, the API accepts a callback function
13 which is invoked once the request completes (with success or failure). This
14 allows the stack to run in a single thread, even when processing dozens of
15 simultaneous requests (not uncommon for an NMT master).
20 The interface between the CANopen stack and the CAN bus (and system clock) is
21 provided by the CAN network object (`can_net_t`/`CANNet`) from the Lely CAN
22 library ([liblely-can]). When the CANopen stack needs to send a CAN frame, it
23 hands it over to a CAN network object, which in turn invokes a user-defined
24 callback function to write the frame to the bus. Similarly, when a user reads a
25 CAN frame from the bus, he gives it to a CAN network object, which in turn
26 distributes it to the registered receivers in the CANopen stack. Additionally,
27 the user periodically checks the current time and tells the CAN network object,
28 which then executes the actions for timers that have elapsed.
30 Sometimes a CANopen application runs on a device which does not have direct
31 access to a CAN bus. [CiA] 315 defines a protocol for tunneling CAN frames over
32 wired or Wireless Transmission Media (WTM). The interface for this protocol can
33 be found in lely/co/wtm.h (#co_wtm_t) and lely/co/wtm.hpp (#lely::COWTM).
34 Additionally, the `can2udp` tool can be run as a daemon or service to act as a
35 proxy between a CAN bus and UDP.
37 The first task when writing a CANopen application is connecting a CAN network
38 object to the CAN bus. The following example shows how to do this using the Lely
39 I/O library ([liblely-io]), which provides a platform-independent interface to
44 #include <lely/util/errnum.h>
45 #include <lely/util/time.h>
46 #include <lely/can/net.h>
47 #include <lely/io/can.h>
48 #include <lely/io/poll.h>
58 int my_can_init(struct my_can *can, const char *ifname);
59 void my_can_fini(struct my_can *can);
61 // This function can be called to perform a single step in an event loop.
62 void my_can_step(struct my_can *can, int timeout);
64 int my_can_on_next(const struct timespec *tp, void *data);
65 int my_can_on_send(const struct can_msg *msg, void *data);
68 my_can_init(struct my_can *can, const char *ifname)
72 // Initialize the I/O library.
73 if (lely_io_init() == -1) {
78 // Open a handle to the CAN bus.
79 can->handle = io_open_can(ifname);
80 if (can->handle == IO_HANDLE_ERROR) {
84 can->st = io_can_get_state(can->handle);
86 // Create a new I/O polling interface.
87 can->poll = io_poll_create();
90 goto error_create_poll;
93 // Create a CAN network object.
94 can->net = can_net_create();
97 goto error_create_net;
100 // Do not block when reading or writing CAN frames and make sure we
101 // receive the frames we sent.
102 io_set_flags(can->handle, IO_FLAG_NONBLOCK | IO_FLAG_LOOPBACK);
104 // Watch the CAN bus for incoming frames.
105 struct io_event event = {
106 .events = IO_EVENT_READ,
107 .u.handle = can->handle
109 io_poll_watch(can->poll, can->handle, &event, 1);
111 struct timespec now = { 0, 0 };
112 // Obtain the current time. This is equivalent to
113 // clock_gettime(CLOCK_REALTIME, &now) from POSIX. To use a steady,
114 // monotonic clock instead, replace all occurrences of the following
116 // clock_gettime(CLOCK_MONOTONIC, &now);
117 timespec_get(&now, TIME_UTC);
118 // Initialize the CAN network clock.
119 can_net_set_time(can->net, &now);
122 // Register my_can_on_next as the function to be invoked when the time
123 // at which the next CAN timer triggers is updated.
124 can_net_set_next_func(can->net, &my_can_on_next, can);
126 // Register my_can_on_send() as the function to be invoked when a CAN
127 // frame needs to be sent.
128 can_net_set_send_func(can->net, &my_can_on_send, can);
132 can_net_destroy(can->net);
135 io_poll_destroy(can->poll);
138 io_handle_release(can->handle);
139 can->handle = IO_HANDLE_ERROR;
148 my_can_fini(struct my_can *can)
150 can_net_destroy(can->net);
153 io_poll_destroy(can->poll);
156 io_handle_release(can->handle);
157 can->handle = IO_HANDLE_ERROR;
163 my_can_step(struct my_can *can, int timeout)
165 struct timespec now = { 0, 0 };
166 timespec_get(&now, TIME_UTC);
167 // Check if a CAN timer is set to expire before the specified timeout.
168 // Ignore if the expiration time is in the past, as that probably
169 // indicates an old timer.
170 int64_t msec = timespec_diff_msec(&can->next, &now);
171 if (msec > 0 && msec < timeout)
174 // Wait at most `timeout` milliseconds for an I/O event to occur.
175 struct io_event event = IO_EVENT_INIT;
176 int n = io_poll_wait(can->poll, 1, &event, timeout);
178 // Update the CAN network clock.
179 timespec_get(&now, TIME_UTC);
180 can_net_set_time(can->net, &now);
182 if (n != 1 || event.u.handle != can->handle)
185 // If the CAN bus is ready for reading, process all waiting frames.
186 if (event.events & IO_EVENT_READ) {
187 struct can_msg msg = CAN_MSG_INIT;
189 while ((result = io_can_read(can->handle, &msg)) == 1)
190 can_net_recv(can->net, &msg);
191 // Treat the reception of an error frame, or any error other
192 // than an empty receive buffer, as an error event.
193 if (!result || (result == -1 && get_errnum() != ERRNUM_AGAIN
194 && get_errnum() != ERRNUM_WOULDBLOCK))
195 event.events |= IO_EVENT_ERROR;
198 // If an error occurred, update the state of the CAN device.
199 if (can->st == CAN_STATE_BUSOFF || (event.events & IO_EVENT_ERROR)) {
200 int st = io_can_get_state(can->handle);
202 if (can->st == CAN_STATE_BUSOFF) {
203 // Recovered from bus off. This is typically
204 // handled by invoking:
205 // co_nmt_on_err(nmt, 0x8140, 0x10, NULL);
206 } else if (st == CAN_STATE_PASSIVE) {
207 // CAN in error passive mode. This is typically
208 // handled by invoking:
209 // co_nmt_on_err(nmt, 0x8120, 0x10, NULL);
217 my_can_on_next(const struct timespec *tp, void *data)
219 struct my_can *can = data;
227 my_can_on_send(const struct can_msg *msg, void *data)
229 struct my_can *can = data;
231 // Send a single frame to the CAN bus.
232 return io_can_write(can->handle, msg) == 1 ? 0 : -1;
238 #include <lely/util/errnum.h>
239 #include <lely/util/time.h>
240 #include <lely/can/net.hpp>
241 #include <lely/io/can.hpp>
242 #include <lely/io/poll.hpp>
244 using namespace lely;
248 explicit MyCAN(const char* ifname)
249 : m_handle(ifname) // Open a handle to the CAN bus.
250 , m_st(m_handle.getState()) // Get the state of the CAN device.
251 , m_poll(new IOPoll) // Create a new I/O polling interface.
252 , m_net(new CANNet) // Create a CAN network object.
254 // Do not block when reading or writing CAN frames and make sure
255 // we receive the frames we sent.
256 m_handle.setFlags(IO_FLAG_NONBLOCK | IO_FLAG_LOOPBACK);
258 // Watch the CAN bus for incoming frames.
259 io_event event = { IO_EVENT_READ, { 0 } };
260 event.u.handle = m_handle;
261 m_poll->watch(m_handle, &event, true);
263 timespec now = { 0, 0 };
264 // Obtain the current time. This is equivalent to
265 // clock_gettime(CLOCK_REALTIME, &now) from POSIX. To use a
266 // steady, monotonic clock instead, replace all occurrences of
267 // the following line with:
268 // clock_gettime(CLOCK_MONOTONIC, &now);
269 timespec_get(&now, TIME_UTC);
270 // Initialize the CAN network clock.
274 // Register the onNext() member function as the function to be
275 // invoked when the time at which the next CAN timer triggers is
277 m_net->setNextFunc<MyCAN, &MyCAN::onNext>(this);
279 // Register the onSend() member function as the function to be
280 // invoked when a CAN frame needs to be sent.
281 m_net->setSendFunc<MyCAN, &MyCAN::onSend>(this);
285 MyCAN(const MyCAN&) = delete;
286 MyCAN& operator=(const MyCAN&) = delete;
288 CANNet* getNet() const noexcept { return m_net.get(); }
290 // This function can be called to perform a single step in an event
293 step(int timeout = 0) noexcept
295 timespec now = { 0, 0 };
296 timespec_get(&now, TIME_UTC);
297 // Check if a CAN timer is set to expire before the specified
298 // timeout. Ignore if the expiration time is in the past, as
299 // that probably indicates an old timer.
300 int64_t msec = timespec_diff_msec(&m_next, &now);
301 if (msec > 0 && msec < timeout)
304 // Wait at most `timeout` milliseconds for an I/O event to
306 io_event event = IO_EVENT_INIT;
307 int n = m_poll->wait(1, &event, timeout);
309 // Update the CAN network clock.
310 timespec_get(&now, TIME_UTC);
313 if (n != 1 || event.u.handle != m_handle)
316 // If the CAN bus is ready for reading, process all waiting
318 if (event.events & IO_EVENT_READ) {
319 can_msg msg = CAN_MSG_INIT;
321 while ((result = m_handle.read(msg)) == 1)
323 // Treat the reception of an error frame, or any error
324 // other than an empty receive buffer, as an error
326 if (!result || (result == -1
327 && get_errnum() != ERRNUM_AGAIN
328 && get_errnum() != ERRNUM_WOULDBLOCK))
329 event.events |= IO_EVENT_ERROR;
332 // If an error occurred, update the state of the CAN device.
333 if (m_st == CAN_STATE_BUSOFF
334 || (event.events & IO_EVENT_ERROR)) {
335 int st = m_handle.getState();
337 if (m_st == CAN_STATE_BUSOFF) {
338 // Recovered from bus off. This is
339 // typically handled by invoking:
340 // nmt->onErr(0x8140, 0x10);
341 } else if (st == CAN_STATE_PASSIVE) {
342 // CAN in error passive mode. This is
343 // typically handled by invoking:
344 // nmt->onErr(0x8120, 0x10);
353 onNext(const timespec* tp) noexcept
361 onSend(const can_msg* msg) noexcept
363 // Send a single frame to the CAN bus.
364 return m_handle.write(*msg) == 1 ? 0 : -1;
369 unique_c_ptr<IOPoll> m_poll;
370 unique_c_ptr<CANNet> m_net;
378 The object dictionary is the central concept of the CANopen protocol. It
379 contains almost the entire state of a CANopen device, including process data and
380 communication parameters. Communication between nodes consists primarily of
381 reading from and writing to each others object dictionary. Even writing CANopen
382 applications is mostly a matter of configuring the object dictionary.
384 Together with the Node-ID, the object dictionary is managed by a CANopen device
385 object (#co_dev_t/#lely::CODev). Although it is possible to construct the object
386 dictionary from scratch with the C and C++ API, it is more convenient to read it
387 from an Electronic Data Sheet (EDS) or Device Configuration File (DCF) (see
388 [CiA] 306). Functions to parse EDS/DCF files can be found in lely/co/dcf.h and
391 Embedded devices often do not have the resources to parse an EDS/DCF file at
392 runtime. Using the `dcf2c` tool it is possible to create a C file containing a
393 static object dictionary, which can be compiled with the application. The static
394 object dictionary can then be converted to a dynamic one at runtime (see
395 lely/co/sdev.h and lely/co/sdev.hpp).
400 The CANopen stack implements the following services:
401 * Process data object (PDO)
402 * Receive-PDO (RPDO):
403 lely/co/rpdo.h (#co_rpdo_t) and lely/co/rpdo.hpp (#lely::CORPDO)
404 * Transmit-PDO (TPDO):
405 lely/co/tpdo.h (#co_tpdo_t) and lely/co/tpdo.hpp (#lely::COTPDO)
406 * Service data object (SDO)
408 lely/co/ssdo.h (#co_ssdo_t) and lely/co/ssdo.hpp (#lely::COSSDO)
410 lely/co/csdo.h (#co_csdo_t) and lely/co/csdo.hpp (#lely::COCSDO)
411 * Synchronization object (SYNC):
412 lely/co/sync.h (#co_sync_t) and lely/co/sync.hpp (#lely::COSync)
413 * Time stamp object (TIME):
414 lely/co/time.h (#co_time_t) and lely/co/time.hpp (#lely::COTime)
415 * Emergency object (EMCY):
416 lely/co/emcy.h (#co_emcy_t) and lely/co/emcy.hpp (#lely::COEmcy)
417 * Network management (NMT):
418 lely/co/nmt.h (#co_nmt_t) and lely/co/nmt.hpp (#lely::CONMT)
419 * Layer setting services (LSS):
420 lely/co/lss.h (#co_lss_t) and lely/co/lss.hpp (#lely::COLSS)
422 While it is possible to create these services by hand, it is almost always more
423 convenient to let them be managed by a single Network Management (NMT) service
424 object (#co_nmt_t/#lely::CONMT). An NMT object manages the state of a CANopen
425 device and creates and destroys the other services as needed.
427 Like all CANopen services, the NMT service gets its configuration from the
428 object dictionary. A typical CANopen application therefore consists of
429 * creating the CAN network object, as we have seen above;
430 * loading the object dictionary form an EDS/DCF file;
431 * creating an NMT service;
432 * and, finally, processing CAN frames in an event loop.
434 Note, however, that a newly created NMT service starts out in the
435 'Initialisation' state and does not create any services or perform any
436 communication. This allows the application to register callback functions before
437 the node becomes operational. The NMT service, including the entire boot-up
438 sequence, can be started by giving it the RESET NODE command.
440 The following example is a minimal CANopen application. Depending on the EDS/DCF
441 file, it can be a simple slave that does nothing besides producing a heartbeat
442 message, or a full-fledged master managing a network of slaves (including
443 automatic firmware upgrades!).
447 #include <lely/util/diag.h>
448 #include <lely/co/dcf.h>
449 #include <lely/co/nmt.h>
456 // Initialize the CAN network.
458 if (my_can_init(&can, "can0") == -1) {
459 diag(DIAG_ERROR, get_errc(), "unable to initialize CAN network");
463 // Load the object dictionary from a DCF file.
464 co_dev_t *dev = co_dev_create_from_dcf_file("test.dcf");
466 diag(DIAG_ERROR, get_errc(), "unable to load object dictionary");
467 goto error_create_dev;
470 // Create the NMT service.
471 co_nmt_t *nmt = co_nmt_create(can.net, dev);
473 diag(DIAG_ERROR, get_errc(), "unable to create NMT service");
474 goto error_create_nmt;
476 // Start the NMT service. We do this by pretending to receive a RESET
477 // NODE command from the master.
478 co_nmt_cs_ind(nmt, CO_NMT_CS_RESET_NODE);
480 // The main event loop.
482 // Process CAN frames in steps of 10 milliseconds.
483 my_can_step(&can, 10);
484 // TODO: do other useful stuff.
504 #include <lely/co/dcf.hpp>
505 #include <lely/co/nmt.hpp>
510 // Initialize the I/O library.
513 // Initialize the CAN network.
516 // Load the object dictionary from a DCF file.
517 auto dev = make_unique_c<CODev>("test.dcf");
519 // Create the NMT service.
520 auto nmt = make_unique_c<CONMT>(can.getNet(), dev.get());
521 // Start the NMT service. We do this by pretending to receive a RESET
522 // NODE command from the master.
523 nmt->csInd(CO_NMT_CS_RESET_NODE);
525 // The main event loop.
527 // Process CAN frames in steps of 10 milliseconds.
529 // TODO: do other useful stuff.
540 As mentioned before, the CANopen stack is asynchronous. Requests return
541 immediately, but take a callback function which is invoked once the request
542 succeeds (or fails). See the documentation of the Lely utilities library
543 ([liblely-util]) for a description of the general callback interface.
545 As an example, define the following callback function for reading a 32-bit
546 unsigned integer from a remote object dictionary:
548 #include <lely/util/diag.h>
549 #include <lely/co/csdo.hpp>
552 onUp(COCSDO* sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
553 co_unsigned32_t ac, co_unsigned32_t val, void* data)
559 // Print an error message if an abort code was received.
560 diag(DIAG_ERROR, 0, "received SDO abort code %08X (%s) when reading object %04X:%02X",
561 ac, co_sdo_ac2str(ac), idx, subidx);
563 // Print the received value on success.
564 diag(DIAG_INFO, 0, "received 0x%08X when reading object %04X:%02X",
569 Before the main event loop we obtain a Client-SDO service object from the NMT
570 service and issue the request:
572 // Wait for the node to be operational.
573 while (nmt->getSt() != CO_NMT_ST_START)
576 // Obtain the first preconfigured Client-SDO connection.
577 auto csdo = nmt->getCSDO(1);
579 // Read the device type (object 1000) from the remote object dictionary.
580 csdo->upReq<co_unsigned32_t, &onUp>(0x1000, 0x00, nullptr);
583 The `upReq()` function returns immediately; `onUp()` is called from the main
584 event loop when the request succeeds (or fails).
586 This is an example for a Client-SDO requests, but all services follow this
587 pattern. Note that by the time the callback function is called, the request has
588 been completed. It is therefore possible to issue a new request directly from
589 the callback function. This pattern is used extensively by the master when
592 [CiA]: http://can-cia.org/
593 [liblely-can]: https://gitlab.com/lely_industries/can
594 [liblely-io]: https://gitlab.com/lely_industries/io
595 [liblely-util]: https://gitlab.com/lely_industries/util