Socket can introduction
What is SocketCan?
Put simply SocketCan is a set of CAN drivers and networking stack that enables can bus appear as a network interfaces on a Linux computer.
For a better and more detailed explanation see wikipedia article
Another feature of SocketCAN is the virtual can interface. This acts like the Ethernet loop-back interface and can be very useful for replaying log files without transmitting them on a physical CAN bus.
Note: The scripts and techniques discussed in this document have only been tested on:
- Raspberry pi 3 B (Revision: a02082)
- Raspbian jessy (2017-03-02)
- PiCAN2 (manufacture link)
- PiCAN2 Duo should work as the second can interface is just a duplicate of the fist using a different SPI CS pin
Setting up the PiCAN2
Make the following changes to the /boot/config.txt file on the Raspberry pi
( sudo nano /boot/config.txt )
enable the spi bus by changing the following line
#dtparam=spi=on to dtparam=spi=on
append the follwing lines to the end of the config.txt file
dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25 dtoverlay=mcp2515-can1,oscillator=16000000,interrupt=24 #this line is only needed for the PiCAN2 Duo dtoverlay=spi-bcm2835-overlay
Setting up the SocketCAN interfaces
Append the follwing lines to the /etc/network/interfaces file
(sudo nano /etc/network/interfaces)
#physical can interfaces allow-hotplug can0 iface can0 can static bitrate 250000 down /sbin/ip link set $IFACE down up /sbin/ifconfig $IFACE txqueuelen 10000
Virtual CAN interface
Append the following lines to the /etc/network/interfaces file
(sudo nano /etc/network/interfaces)
#virtual can interfaces auto vcan0 iface vcan0 inet manual pre-up /sbin/ip link add dev $IFACE type vcan up /sbin/ifconfig $IFACE up
If this has worked correctly (a reboot may be needed) in addition to the regular Ethernet interfaces, ifconfig should display the following
pi@raspberrypi:~ $ ifconfig can0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 UP RUNNING NOARP MTU:16 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:10 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) vcan0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 UP RUNNING NOARP MTU:16 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Install the CANboat project
step 2 is optional but will keep your home directory a little tidier
setp 3 is needed for the raspberry pi 3 but may not be needed on other Linux distros
1. get the latest package repository catalogue with the command
sudo apt-get update
2. create a folder to hold the CANboat project
mkdir ~/canboat cd ~/canboat
3. install required module for the compiler with the command
sudo apt-get install xsltproc
4. clone and build CANboat
git clone git://github.com/canboat/canboat cd canboat sudo make sudo make install
CANboat should now be good to go.
Testing the interface
A warning about timing issues
the NMEA2000 CAN bus normally runs at 250Kb/s so if you just issue the following command,
cat canlog.log | socketcan-writer vcan0
then (with the hardware used here) CANboat will only receive/decode approx 25% of the messages transmitted, if you slow the rate of transmission down it solves the problem.
Python script for replaying a log and slowing transmission
The following is a realy simple python script will read a log file (fName) and write each line to stdout with a 0.025 second delay between lines.
to create the script do the following in a suitable folder on your system
touch logReplay.py chmod 775 logReplay.py (note you will want to chose apropreate permissions) nano logReplay.py
copy the following into the file
#!/usr/bin/env python from time import sleep from sys import * #This is a simple script to re-play a logfile to stdout with a delay between each line fName = './aava-n2k.data' delaySec = 0.025 f = open( fName, 'r') for ln in f: stdout.write(ln) sleep(delaySec)
Transmitting messages to socket can interface
For testing purposes we are using the vcan0 interface if you wish to transmit on the physical bus use can0 / can1 instead
logPlay.py | SocketCAN-writer vcan0
Expected errors
Some serial interfaces (Actisense NGT-1) add proprietary messages that are in addition to what was transmitted on the CAN bus, these are distinguished by having a PGN > 16384 (0x4000). If these are sent to CANboat’s socketcan-writer it will throw and error skip the message.
ERROR 2017-05-17T15:35:37.332Z [socketcan-writer] Invalid PGN, too big (0x400f2). Skipping.
Logging received messages
issue the following command will pipe the output from candump to a logfile
candump vcan0 | .fileNameOfLog.File
Setting signalK to listen to a socket can adapter
The json sample below should act as a templete signalK pipedProvder, repalce vcan0 with the aproprate socket can interface.
Restart the signalK server, then when you replay a log file or messages appear on the CAN bus and they should apear in signalK
{ "id": "n2k-vcan0", "pipeElements": [ { "type": "providers/execute", "options": { "command": "candump vcan0 | candump2analyzer " } }, { "type": "providers/liner", "options": { "rawlogging": true, "logdir": "logs", "discriminator": "2" } }, { "type": "providers/n2kAnalyzer" }, { "type": "providers/n2k-signalk" } ] }