openCANopen
Features
- CANopen master
- Network management
- Automatic discovery of nodes on network
- Dynamically loadable drivers
- SDO client with expediated and segmented mode transfer
- EDS reader
- REST interface for accessing object-dictionary based on EDS
- Virtual CANopen nodes for testing
- SDO server with expediated and segmented mode transfer
- Virtual nodes are configurable via ini files
- CAN-TCP bridge
- Transfers raw CAN frames over TCP
- Traffic monitoring
- A tool is included to monitor and interpret CANopen traffic
- Supports Linux Socket CAN
- Can be ported to other platforms with little effort
Architecture
The system is mostly asynchronous but some things are implemented synchronously via worker threads.
Non-blocking tasks are handled in a single main loop. The main loop sends blocking tasks to a single work queue. The work queue is a stable priority queue implemented using a heap. When a worker is ready (which is most of the time), it grabs a job from the queue. When it's done, it sends the result back to the main loop.
Using the Code
Currently, the internals of the CANopen master are not available as a library, but they are fairly independent of each other so they can be used in isolation. Some components require a main loop library. The one that is provided with the project can be run within another main loop using mloop_get_pollfd(struct mloop*)
and mloop_run_once(struct mloop*)
. Mloop is implemented using epoll, so it would have to be implemented using a different method when porting to other platforms.
All components can be executed in an asynchronous fashion. Some components, such as SDO requests, can be executed synchronously.
Writing Drivers
The API can be found in inc/canopen-driver.h. It lacks documentation but the names should be quite revealing.
A driver's DSO file should be named co_drv_name.so where "name" is the lower case name of the node according to the object dictionary. Place the DSO under /usr/lib/canopen.
The driver needs to implement the function int co_drv_init(struct co_drv*)
. The function shall return a number less than 0 on error and 0 on success. Use the init function to initialise event handlers for PDO, EMCY, etc. and set up the node via SDO.
The SDO interface is asynchronous and follows a request-reply pattern. A callback function must be set for each request.
See example-driver.c
Building
# make -f Makefile.opensource
Installing
# make install -f Makefile.opensource
Running
# canopen-master can0