diff --git a/.gitignore b/.gitignore index b51f1ca..7f41b3d 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ GNUmakefile.in /slcan_attach /slcand /slcanpty +/testj1939 /can-utils-*.tar.bz2 /can-utils-*.tar.gz diff --git a/GNUmakefile.am b/GNUmakefile.am index a4c50a1..29b7570 100644 --- a/GNUmakefile.am +++ b/GNUmakefile.am @@ -63,7 +63,8 @@ bin_PROGRAMS = \ log2long \ slcan_attach \ slcand \ - slcanpty + slcanpty \ + testj1939 jacd_LDADD = libj1939.la jspy_LDADD = libj1939.la @@ -73,7 +74,9 @@ EXTRA_DIST = \ .travis.yml \ Android.mk \ README.md \ - autogen.sh + autogen.sh \ + can-j1939-kickstart.md + can-j1939.md MAINTAINERCLEANFILES = \ configure \ diff --git a/Makefile b/Makefile index b8853df..a63f72a 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ CPPFLAGS += -Iinclude \ PROGRAMS_ISOTP = isotpdump isotprecv isotpsend isotpsniffer isotptun isotpserver isotpperf PROGRAMS_CANGW = cangw PROGRAMS_SLCAN = slcan_attach slcand -PROGRAMS_J1939 = jacd jspy jsr +PROGRAMS_J1939 = jacd jspy jsr testj1939 PROGRAMS = can-calc-bit-timing candump cansniffer cansend canplayer cangen canbusload\ log2long log2asc asc2log\ canlogserver bcmserver\ diff --git a/can-j1939-kickstart.md b/can-j1939-kickstart.md new file mode 100644 index 0000000..7ea75ff --- /dev/null +++ b/can-j1939-kickstart.md @@ -0,0 +1,216 @@ +# Kickstart guide to can-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](testj1939.c) + +When *can-j1939* is compiled as module, opening a socket will load it, +__or__ you can load it manually + + modprobe can-j1939 + +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 + +Binding a can-j1939 socket to a source address will register +allow you to send packets. + + ./testj1939 can0:0x80 + +Your system had, for a small moment, source address 0x80 assigned. + +### 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,0x3ffff + +This produces **1BFFFF80#0123456789ABCDEF** on CAN. + +### Multiple source addresses on 1 CAN device + + ./testj1939 -s can0:0x90,0x3ffff + +produces **1BFFFF90#0123456789ABCDEF** , + +### Use PDU1 PGN + + ./testj1939 -s can0:0x80,0x12345 + +emits **1923FF80#0123456789ABCDEF** . + +Note that the real PGN is **0x12300**, and destination address is **0xff**. + +### Use destination address info + +The destination field may be set during sendto(). +*testj1939* implements that like this + + ./testj1939 -s can0:0x80,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:0x80,0x12300 :,0x32100 + +emits **1B21FF80#0123456789ABCDEF** rather than 1923FF80#012345678ABCDEF + +Desitination specific transmissions + + ./testj1939 -s can0:0x80,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 + +This is the first fragment for broadcasted *Transport Protocol*. +_testj1939_ returns before the subsequent packets can leave, and +as the last socket on the system closes, can-j1939 effectively +cleans up all resources. Real-world applications will run like forever, +and will not encounter this side-effect. + +Try again, and instruct _testj1939_ to keep the socket open for 1 second. + + ./testj1939 -w1.0 -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. + +First assign 0x90 to the local system. +This becomes important because the kernel must interact in the +transport protocol sessions before the complete packet is delivered. + + ./testj1939 can0:0x90 -r & + +Now test: + + ./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 + +### using connect + +### advanced filtering + +## dynamic addressing + diff --git a/can-j1939.md b/can-j1939.md new file mode 100644 index 0000000..3e8fcfb --- /dev/null +++ b/can-j1939.md @@ -0,0 +1,132 @@ +# CAN-J1939 on linux + +The [Kickstart guide is here](can-j1939-kickstart.md) + +## CAN on linux + +See [Wikipedia:socketcan](http://en.wikipedia.org/wiki/Socketcan) + +## 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 **29**bit, 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](http://man7.org/linux/man-pages/man2/getsockname.2.html)) + * DA+PGN is put in peername ([getpeername](http://man7.org/linux/man-pages/man2/getpeername.2.html)) + 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 (obsolete!) + +CAN has no protocol id field. +The can-j1939 stack only activates when a socket opens +for a network device. + +The methods described here existed in earlier implementations. + +### netlink + + ip link set can0 j1939 on + +This method is obsoleted in favor of _on socket connect_. + +### 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 (obsolete!) + +Older versions of can-j1939 used a modified iproute2 +for manipulating the kernel lists of current addresses. + +### Static addressing + + ip addr add j1939 0x80 dev can0 + +### Dynamic addressing + + ip addr add j1939 name 0x012345678abcdef dev can0 + diff --git a/page.theme b/page.theme new file mode 100644 index 0000000..e850a9b --- /dev/null +++ b/page.theme @@ -0,0 +1,21 @@ + + +
+