CANopen
CANopen is a specific protocol built on top of CAN bus, widely used to coordinate simple field devices - drives, I/O modules, sensors - that share a single bus. The CANopen specification defines an Object Dictionary (OD), and this driver honors that structure through index and sub-index addressing of fields. It does not ship an Electronic Data Sheet (EDS) parser, leaving that to applications that wish to utilize one.
Supported Operations
| Name | Value | Description |
|---|---|---|
CANopen SDO |
|
SDO are request/response conversations. Both read and write path is supported. |
CANopen PDO |
|
PDO messages are broadcasted to the bus and have to be mapped at application layer. |
|
|
Connection String
The connection string layout is canopen:<transport-code>://<transport-address>.
-
canopen:can-socketcan://can0 -
canopen:can-virtualcan://test
The interface and the bus name can also be given as options - can-socketcan.interface-name and
can-virtualcan.bus-name - for callers that assemble a connection string out of options alone.
The address segment wins if both name one.
Connection String Options
Name |
Type |
Default Value |
Required |
Description |
Name |
CANopen |
|||
Code |
|
|||
Maven Dependency |
<dependency> <groupId>org.apache.plc4x</groupId> <artifactId>plc4j-driver-canopen</artifactId> <version>1.0.0</version> </dependency> |
|||
Default Transport |
|
|||
Supported Transports |
|
|||
Config options: |
||||
|
INT |
CAN node identifier. Depending on used CAN version it might be 11 or 29 bit unsigned int. |
||
|
INT |
1000 |
Time after which dispatched BUS operation (ie. SDO request) will be marked as failed. |
|
Transport config options: |
||||
can-socketcan |
||||
|
STRING |
Linux CAN interface name (e.g., "can0", "vcan0"). Alternative to naming the interface in the address segment of the connection string, which takes precedence. |
||
|
BOOLEAN |
false |
Share CAN socket across multiple transport instances on the same interface |
|
|
INT |
1000 |
Read timeout in milliseconds for blocking reads on the CAN socket |
|
|
STRING |
Comma-separated list of accepted CAN IDs (decimal or 0x hex). Empty means accept all. |
||
|
INT |
-1 |
Start of accepted CAN ID range (inclusive). -1 means no range filtering. |
|
|
INT |
-1 |
End of accepted CAN ID range (inclusive). -1 means no range filtering. |
|
can-virtualcan |
||||
|
STRING |
default |
Name of the virtual CAN bus. Instances on the same bus exchange frames in-memory. |
|
|
STRING |
Comma-separated list of accepted CAN IDs (decimal or 0x hex). Empty means accept all. |
||
|
INT |
-1 |
Start of accepted CAN ID range (inclusive). -1 means no range filtering. |
|
|
INT |
-1 |
End of accepted CAN ID range (inclusive). -1 means no range filtering. |
|
Tag Addresses
Addressing is implemented in Java. See the protocol support matrix for what each implementation does.
General Format
CANopen specification defines several groups of addresses dedicated to certain kind of operations. Critical services and message exchanges related with them have lower identifiers making them wining eventual bus access.
SDO addresses request/response reads and writes against a single Object Dictionary entry: SDO:nodeId:index/subindex:type[arraySize].
Both expedited and segmented transfer modes are supported, chosen automatically based on payload length; block transfer is not supported.
All numeric values - nodeId, index, subindex - can be specified using hexadecimal notation (ie. 0xA). An optional /answerNodeId after the
node ID lets the response be expected from a different node than the request was sent to.
PDO addresses identify one of the four transmit or receive PDO channels of a node: TRANSMIT_PDO_1:nodeId:type[arraySize] through
RECEIVE_PDO_4:nodeId:type[arraySize]. PDO is an asynchronous broadcast, so receiving it requires a subscription; a subscriber is notified
with the value mapped to the type given in the address.
NMT addresses target the Network Management service, which is broadcast using CAN node ID 0 and carries the highest priority on the bus.
The syntax is NMT or NMT:nodeId; omitting the node ID (or using 0) is a wildcard that subscribes to state updates for all bus
participants. A subscription receives a structure with two fields, node (USINT) and state (USINT). Writable values indicate the
requested NMT state and are supplied as USINT: 0x01 START, 0x02 STOP, 0x80 PRE_OPERATIONAL, 0x81 RESET_NODE, 0x82
RESET_COMMUNICATION. The NMTStateRequest enumeration can be used on the application side instead of the plain numbers.
Heartbeat addresses subscribe to the lowest-priority service on the bus, which still indicates a node’s operating state (booted,
operational). The syntax is HEARTBEAT or HEARTBEAT:nodeId; as with NMT, omitting the node ID (or using 0) subscribes to all bus
participants. A subscription receives the same two-field structure as NMT: node (USINT) and state (USINT).
Data Types
CANopen defines its own set of data types, which this driver maps onto PLC4X types as follows:
CANopen Type |
Length (in bits) |
PLC4X Type |
BOOLEAN |
1 |
BOOL |
UNSIGNED8 |
8 |
USINT |
UNSIGNED16 |
16 |
UINT |
UNSIGNED24 |
24 |
UDINT |
UNSIGNED32 |
32 |
UDINT |
UNSIGNED40 |
40 |
ULINT |
UNSIGNED48 |
48 |
ULINT |
UNSIGNED56 |
56 |
ULINT |
UNSIGNED64 |
64 |
ULINT |
INTEGER8 |
8 |
SINT |
INTEGER16 |
16 |
INT |
INTEGER24 |
24 |
DINT |
INTEGER32 |
32 |
DINT |
INTEGER40 |
40 |
LINT |
INTEGER48 |
48 |
LINT |
INTEGER56 |
56 |
LINT |
INTEGER64 |
64 |
LINT |
REAL32 |
32 |
REAL |
REAL64 |
64 |
LREAL |
RECORD |
8 * size |
BYTE |
OCTET_STRING |
8 * size |
STRING (UTF-8) |
VISIBLE_STRING |
8 * size |
STRING (UTF-8) |
TIME_OF_DAY |
unsupported |
|
TIME_DIFFERENCE |
unsupported |
|
UNICODE_STRING |
8 * size |
STRING (UTF-8) |
All string types are decoded using UTF-8 encoding regardless of their kind (octet, visible, unicode).
In case a device returns text using a different encoding, it is recommended to use the RECORD type and construct the text manually above PLC4X.
The size of variable-length structures is automatically assumed to be the full length of the SDO answer.
When writing, the length of the field can be omitted; for example write(SDO:1:2/3:RECORD, payload) will try to write the whole payload to the specified address.
The same applies to responses sent by devices, as the requester often does not know the full length of the reply payload beforehand.
Examples
-
SDO:20:0x10/0xAA:RECORD- read/write the object at index0x10, sub-index0xAAon node 20 as aRECORD. -
SDO:20/22:0x10/0xAA:RECORD- same object, but the response is expected from node 22 instead of node 20. -
SDO:20:0x30/40:BOOLEAN- object at index0x30, sub-index40(decimal) on node 20, as aBOOLEAN. -
RECEIVE_PDO_2:20:RECORD- the second receive PDO of node 20, mapped as aRECORD. -
NMT:20- subscribe to or write NMT state changes of node 20. -
NMT- subscribe to NMT state changes of every node on the bus (wildcard). -
HEARTBEAT- subscribe to heartbeat messages of every node on the bus (wildcard).
Protocol Details
CAN, despite (or due) to its popularity has ambiguous meaning. There are multiple articles and sources which attempts to give introduction, yet very few of them is consistent between each other.
There are two dominant formats of frames - CAN 2.0A and 2.0B:
-
CAN 2.0A uses 11 bit identifier and up to 8 bytes of data.
-
CAN 2.0B uses 29 bit identifier and up to 8 bytes of data.
To make things worse with introduction of CAN FD amount of combinations increased even more. Double check frame format as this integration supports CANopen and does not support CANopen FD nor CAN 2.0B.
Further reading on CAN flavors: https://en.wikipedia.org/wiki/CAN_bus
Default transport used with this protocol is socketcan. Currently, only 2.0A format (up to 8 bytes of data) is supported.
Implemented driver supports currently socketcan transport. Change of transport requires code modifications and injection of new "transport" type which will encode CANopen payloads to specific frame format.
Socketcan seems to be most widespread way to access CAN bus. It also masks different hardware variants which might come with their own drivers.