CAN-Bus mit Linux und Python Grazer Linuxtage 2014 Jörg Faschingbauer 1 / 31
Inhaltsverzeichnis 1 Basics 2 CAN Interfaces 3 Programmierung 4 Hardware, Kernel 5 Schluss 2 / 31
Basics Übersicht 1 Basics 2 CAN Interfaces 3 Programmierung 4 Hardware, Kernel 5 Schluss 3 / 31
Basics Warum dieser Vortrag? Schamlose Werbung Jörg Faschingbauer jf@faschingbauer.co.at www.faschingbauer.co.at Es ist alles sehr kompliziert ( c Fred Sinowatz)... wenn man alles vermischt CAN-Bus wird nicht mit Einfachheit in Verbindung gebracht Linux bringt Einfachheit rein Netzwerkprogrammierung Allgemeinwissen SocketCAN : gespendet von Volkswagen Keine Bindung der Applikation an Hardware Freie Wahl der Programmiersprache natürlich Python Spezielles Goodie: Virtueller CAN-Bus Entwickeln und Testen am PC, ganz ohne Hardware 4 / 31
Basics Halbherzig: Geschichte aus Wikipedia jjj hier noch was her 5 / 31
Basics Netzwerkprogrammierung: Datagrammverkehr Paketvermittlung Datagramme Am Internet: User Datagram Protokoll (UDP) Keine Point-to-Point Verbindung wie TCP Broadcasts möglich Paketgrenzen 6 / 31
Basics Und CAN? Sehr kleine Pakete (bis 8 Bytes Nutzdaten) Bus-Arbitrierung, Priorität und Applikationszuordnung anhand von Paket-IDs Keine Adressen nur Broadcasts = sieht aus wie ein Netzwerk, ist ein Netzwerk 7 / 31
Basics Ein Netzwerkpaket... Definiert als C-Struct Host-Byteorder Python: struct.pack(), struct.unpack() #include <linux/can.h> struct can_frame { canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ u8 can_dlc; /* frame payload length */ u8 data[8] attribute ((aligned(8))); }; 8 / 31
CAN Interfaces Übersicht 1 Basics 2 CAN Interfaces 3 Programmierung 4 Hardware, Kernel 5 Schluss 9 / 31
CAN Interfaces Das CAN-Interface: Konfiguration CAN ist ein Netzwerk... # ip link show... alle interfaces hier... # ip link show can0 3: can0: <NOARP,ECHO> mtu 16 qdisc noop state DOWN mode DEFAUL link/can # ip link set can0 type can help # ip link set can0 bitrate 500000 # ip link set can0 bitrate 500000 listen-only on # ip link set can0 up 10 / 31
CAN Interfaces CAN Utils (1) Nette kleine Utilities... git@gitorious.org:linux-can/can-utils.git Überbleibsel des SocketCAN Projektes ( CAN als Netzwerk ) cansend: Frame senden candump: Aufzeichnen aus 1.. Interfaces canplayer: Replay aus Logfile... und einige andere Testen der Konfiguration... und mit Fantasie mehr 11 / 31
CAN Interfaces CAN Utils (2) Frames generieren: $ cansend can0 42#deadbeef $ cangen -D deadbeef -L 4 can0 $ cangen -D deadbeef -L 4 -I 42 can0 $ cangen -D i -I 42 -L 8 -g 100 -p 100 can0 Frames mitschnüffeln: $ candump can0 $ candump can0 can1... 12 / 31
CAN Interfaces CAN Utils (3) Record, Replay: $ candump -L can0 > can0.log $ canplayer <./can0.log Wechseln des Interfaces: $ canplayer can1=can0 <./can0.log 13 / 31
CAN Interfaces vcan: Virtuelles CAN-Interface Problem: Lösung: CAN-Programmierung braucht Hardware... mindestens zwei Teilnehmer (oder Loopback über Controller) Programmieren und Testen so schwer wie möglich # modprobe vcan # ip link add dev mein-test-can type vcan # canplayer mein-test-can=can0 <./can0.log Fantasie: Programmieren und Testen zuhause am PC Continuous Integration... 14 / 31
Programmierung Übersicht 1 Basics 2 CAN Interfaces 3 Programmierung 4 Hardware, Kernel 5 Schluss 15 / 31
Programmierung CAN Programmierung CAN geht über Sockets... Paketvermittlung ähnlich wie UDP Neue Protocol Family: PF CAN Keine Adressen Binden per Interface Index Pakete ( Frames ) von fixer Größe 16 / 31
Programmierung CAN in C Socket, Interface Index Documentation/networking/can.txt int s; struct sockaddr_can addr; struct ifreq ifr; s = socket(pf_can, SOCK_RAW, CAN_RAW); strcpy(ifr.ifr_name, "can0"); ioctl(s, SIOCGIFINDEX, &ifr); addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; bind(s, (struct sockaddr *)&addr, sizeof(addr)); 17 / 31
Programmierung CAN in Python Socket, Interface Index can_socket = socket.socket( socket.pf_can, socket.sock_raw, socket.can_raw) can_socket.bind(( can0,)) 18 / 31
Programmierung CAN in C Frames (1) Kernel liefert (und akzeptiert) Netzwerkpakete fixer Größe CAN Frames #include <linux/can.h> struct can_frame { canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ u8 can_dlc; /* frame payload length */ u8 data[8] attribute ((aligned(8))); }; 19 / 31
Programmierung CAN in C Frames (2) struct can_frame frame; read(s, &frame, sizeof(struct can_frame)); /* do something with frame */ write(s, &frame, sizeof(struct can_frame)); 20 / 31
Programmierung CAN in Python Frames struct can_frame { canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ u8 can_dlc; /* frame payload length */ u8 data[8] attribute ((aligned(8))); }; frame_layout = "=IB3x8s" frame_size = struct.calcsize(frame_layout) frame = can_socket.recv(frame_size) can_id, can_dlc, data = struct.unpack(frame_layout, frame) /* do something with frame */ frame = struct.pack(frame_layout, can_id+1, len(data), data) can_socket.send(frame) 21 / 31
Programmierung Was gibts noch zu sagen? Interface Index 0 (Python: leerer Interface-Name, ) alle Interfaces Alternative System Calls: recvfrom(), sendto(), wenn man am Interface interessiert ist Der Rest ist Unix Filedescriptoren Event Loops Client-Server Techniken, die altbekannt sind Realtime... hat nix damit zu tun Kann man machen, wenn man will/muss Vorsicht: soll man nicht, wenn man nicht muss 22 / 31
Hardware, Kernel Übersicht 1 Basics 2 CAN Interfaces 3 Programmierung 4 Hardware, Kernel 5 Schluss 23 / 31
Hardware, Kernel MCP2515: Schaltplan http://lnxpps.de/can2udpe/openwrt/ 24 / 31
Hardware, Kernel MCP2515: Löterei 25 / 31
Hardware, Kernel MCP2515: SPI Serial Peripheral Interface SPI SPI: asymmetrisch (Master/Slave) MOSI, MISO, SCLK: SPI an sich Chip Select ( Slave Select ) Benachrichtigung an Master Interrupt Raspi: beliebiger GPIO 26 / 31
Hardware, Kernel MCP2515: Raspberry Raspberry P1 Pinout Broadcom BCM2835 2 SPI Master, davon einer über Header P1 erreichbar 2 Chip-Select CE0 ( Chip Enable ) Haufenweise IO GPIO25 Stromversorgung 3.3V für MCP2515 5V für Transceiver 27 / 31
Hardware, Kernel Arbeiten am Kernel Board File : Verdrahtung der Software mit Hardware C Code Hauptsächlich Strukturen in Analogie zur Hardware Raspberry Board File: arch/arm/mach-bcm2708/bcm2708.c MCP2515 Driver: drivers/net/can/mcp251x.c http://github.com/jfasch/linux/tree/rpi-mcp2515 28 / 31
Schluss Übersicht 1 Basics 2 CAN Interfaces 3 Programmierung 4 Hardware, Kernel 5 Schluss 29 / 31
Schluss Weiterführendes SocketCAN: http://en.wikipedia.org/wiki/socketcan CAN-Utils: https://gitorious.org/linux-can/can-utils Kernel Doc: Documentation/networking/can.txt (im Kernel Source) Python-CAN: http://python-can.readthedocs.org OBD II: http://de.wikipedia.org/wiki/on-board-diagnose 30 / 31
Schluss Viel Spass 31 / 31