|
|
||
|---|---|---|
| .gitignore | ||
| LICENSE | ||
| Makefile | ||
| Readme.md | ||
| page.theme | ||
| style.css | ||
| testj1939.c | ||
Readme.md
CAN-J1939 on linux
CAN on linux
J1939 networking in short
-
Add addressing on top of CAN (destination address & broadcast)
-
Any (max 1780) length packets. Packets of 9 or more use Transport Protocol (fragmentation) Such packets use different CANid for the same PGN.
-
only 29bit, non-RTR CAN frames
-
CAN id is composed of
- 0..8: SA (source address)
- 9..26:
- PDU1: PGN+DA (destionation address)
- PDU2: PGN
- 27..29: PRIO
-
SA / DA may be dynamically assigned via j1939-81
Fixed rules of precedence in Specification, no master necessary
J1939 on SocketCAN
J1939 is just another protocol that fits in the Berkely sockets.
socket(AF_CAN, SOCK_DGRAM, CAN_J1939)
differences from CAN_RAW
addressing
SA, DA & PGN are used, not CAN id.
Berkeley socket API is used to communicate these to userspace:
- SA+PGN is put in sockname (getsockname)
- DA+PGN is put in peername (getpeername)
PGN is put in both structs
PRIO is a datalink property, and irrelevant for interpretation Therefore, PRIO is not in sockname or peername.
The data that is [recv][recvfrom] or [send][sendto] is the real payload. Unlike CAN_RAW, where addressing info is data.
Packet size
J1939 handles packets of 8+ bytes with Transport Protocol fragmentation transparently. No fixed data size is necessary.
send(sock, data, 8, 0);
will emit a single CAN frame.
send(sock, data, 9, 0);
will use fragementation, emitting 1+ CAN frames.
Enable j1939
CAN has no protocol id field. Enabling protocols must be done manually
netlink
ip link set can0 j1939 on
procfs for legacy kernel (2.6.25)
This API is dropped for kernels with netlink support!
echo can0 > /proc/net/can-j1939/net
Using J1939
BSD socket implementation
- socket
- bind / connect
- recvfrom / sendto
- getsockname / getpeername
Modified struct sockaddr_can
struct sockaddr_can {
sa_family_t can_family;
int can_ifindex;
union {
struct {
__u64 name;
__u32 pgn;
__u8 addr;
} j1939;
} can_addr;
}
-
can_addr.j1939.pgn is PGN
-
can_addr.j1939.addr & can_addr.j1939.name
determine the ECU-
receiving address information,
addr is always set,
name is set when available. -
When providing address information,
name != 0 indicates dynamic addressing
-
iproute2
Static addressing
ip addr add j1939 0x80 dev can0
Dynamic addressing
ip addr add j1939 name 0x012345678abcdef dev can0
Kickstart guide to j1939 on linux
Prepare using VCAN
You may skip this step entirely if you have a functional can0 bus on your system.
Load module, when vcan is not in-kernel
modprobe vcan
Create a virtual can0 device and start the device
ip link add can0 type vcan
ip link set can0 up
First steps with j1939
Use testj1939
When can-j1939 is compiled as module, load it.
modprobe can-j1939
Enable the j1939 protocol stack on the CAN device
ip link set can0 j1939 on
Most of the subsequent examples will use 2 sockets programs (in 2 terminals). One will use CAN_J1939 sockets using testj1939, and the other will use CAN_RAW sockets using cansend+candump.
testj1939 can be told to print the used API calls by adding -v program argument.
receive without source address
Do in terminal 1
./testj1939 -r can0:
Send raw CAN in terminal 2
cansend can0 1823ff40#0123
You should have this output in terminal 1
40 02300: 01 23
This means, from NAME 0, SA 40, PGN 02300 was received, with 2 databytes, 01 & 02.
now emit this CAN message:
cansend can0 18234140#0123
In J1939, this means that ECU 0x40 sends directly to ECU 0x41 Since we did not bind to address 0x41, this traffic is not meant for us and testj1939 does not receive it.
Use source address
./testj1939 can0:0x80
will say
./testj1939: bind(): Cannot assign requested address
Since J1939 maintains addressing, 0x80 has not yet been assigned as an address on can0 . This behaviour is very similar to IP addressing: you cannot bind to an address that is not your own.
Now tell the kernel that we own address 0x80. It will be available from now on.
ip addr add j1939 0x80 dev can0
./testj1939 can0:0x80
now succeeds.
receive with source address
Terminal 1:
./testj1939 -r can0:0x80
Terminal 2:
cansend can0 18238040#0123
Will emit this output
40 02300: 01 23
This is because the traffic had destination address 0x80 .
send
Open in terminal 1:
candump -L can0
And to these test in another terminal
./testj1939 -s can0:0x80
This produces 1BFFFF80#0123456789ABCDEF on CAN.
./testj1939 -s can0:
will produce exactly the same because 0x80 is the only address currently assigned to can0: and is used by default.
Multiple source addresses on 1 CAN device
ip addr add j1939 0x90 dev can0
./testj1939 -s can0:0x90
produces 1BFFFF90#0123456789ABCDEF ,
./testj1939 -s can0:
still produces 1BFFFF80#0123456789ABCDEF , since 0x80 is the default source address. Check
ip addr show can0
emits
X: can0: <NOARP,UP,LOWER_UP> mtu 16 qdisc noqueue state UNKNOWN
link/can
can-j1939 0x80 scope link
can-j1939 0x90 scope link
0x80 is the first address on can0.
Use specific PGN
./testj1939 -s can0:,0x12345
emits 1923FF80#0123456789ABCDEF .
Note that the real PGN is 0x12300, and destination address is 0xff.
Emit destination specific packets
The destination field may be set during sendto(). testj1939 implements that like this
./testj1939 -s can0:,0x12345 can0:0x40
emits 19234080#0123456789ABCDEF .
The destination CAN iface must always match the source CAN iface. Specifing one during bind is therefore sufficient.
./testj1939 -s can0:,0x12300 :0x40
emits the very same.
Emit different PGNs using the same socket
The PGN is provided in both bind( sockname ) and sendto( peername ) , and only one is used. peername PGN has highest precedence.
For broadcasted transmissions
./testj1939 -s can0:,0x12300 :,0x32100
emits 1B21FF80#0123456789ABCDEF rather than 1923FF80#012345678ABCDEF
Desitination specific transmissions
./testj1939 -s can0:,0x12300 :0x40,0x32100
emits 1B214080#0123456789ABCDEF .
It makes sometimes sense to omit the PGN in bind( sockname ) .
Larger packets
J1939 transparently switches to Transport Protocol when packets do not fit into single CAN packets.
./testj1939 -s20 can0:0x80 :,0x12300
emits:
18ECFF80#20140003FF002301
18EBFF80#010123456789ABCD
18EBFF80#02EF0123456789AB
18EBFF80#03CDEF01234567
The fragments for broadcasted Transport Protocol are seperated
50ms from each other.
Destination specific Transport Protocol applies flow control
and may emit CAN packets much faster.
./testj1939 -s20 can0:0x80 :0x90,0x12300
emits:
18EC9080#1014000303002301
18EC8090#110301FFFF002301
18EB9080#010123456789ABCD
18EB9080#02EF0123456789AB
18EB9080#03CDEF01234567
18EC8090#13140003FF002301
The flow control causes a bit overhead. This overhead scales very good for larger J1939 packets.
Advanced topics with j1939
Change priority of J1939 packets
./testj1939 -s can0:0x80,0x0100
./testj1939 -s -p3 can0:0x80,0x0200
emits
1801FF80#0123456789ABCDEF
0C02FF80#0123456789ABCDEF