===== Raspberry Pi and Linux Kernel AX.25 support ===== This page documents how to set up a Raspberry Pi running Raspberry Pi OS Lite (32 bit), and was written by Szymon M0GZP. It is possible to do this on 64 bit Raspberry Pi OS as well, so long as you are consistently using 32 bit or 64 bit throughout; see the notes below. Alternative reading: [[https://www.elite.uk.com/mike/posts/linux-netrom-setup/|Mike has also written up]] a guide on his own site for configuring all the bits. There is also documentation in TLDP: [[https://tldp.org/HOWTO/Netrom-Node-5.html]] ==== Equipment ==== This example setup consists of: * Raspberry Pi 4b * CG Antenna 2000 Radio Interface * Behringer UMC202HD Audio Interface * Tait 2010 VHF Radio * ICOM IC7300 HF Radio but the same principles apply with different radios, audio and radio interfaces. ==== Software Prereqs ==== ''sudo apt install libax25 ax25-apps ax25-tools socat direwolf'' You do not need to install socat or direwolf packages if you will be using a hardware TNC such as NinoTNC. Notes: * make absolutely certain that you are using a 32bit kernel if you have 32bit user binaries. I somehow ended up with a 64bit kernel and things broke in very subtle ways. Check that ''uname -m'' returns ''armv7l'' if you installed a 32bit OS! * you currently need to use ''rpi-update'' to get the latest series 6 kernel - there are unfixed AX.25 bugs in the version 5 kernel available at the time of writing. ==== TNC ==== The author uses Dire Wolf to run the two radios. Dire Wolf is a fundamentally a KISS modem implemented in software and using a sound card. An alternative to using a sound card based KISS modem is to use a hardware device such as NinoTNC. The same overall steps still apply, just using a piece of hardware as the modem instead of a piece of software. Here is a suitable Dire Wolf config: ADEVICE plughw:1,0 ACHANNELS 1 ADEVICE1 plughw:4,0 ACHANNELS 1 CHANNEL 0 MYCALL M0GZP MODEM 1200 PTT /dev/ttyUSB0 RTS CHANNEL 2 MYCALL M0GZP-1 MODEM 300 7@30 E PTT RIG 3073 /dev/ttyUSB1 IL2PTX AGWPORT 0 KISSPORT 8001 0 KISSPORT 8002 2 This sets up two channels: * ''CHANNEL 0'' talks to sound card ''plughw:1,0'' (which is the UMC202HD) and does PTT on ''/dev/ttyUSB0'' (which is the CG Antenna 2000) * ''CHANNEL 1'' talks to sound card ''plughw:4,0'' (which is the 7300) and does PTT on ''/dev/ttyUSB1'' (which is the 7300) It also disables AGW, and sets up two KISS listeners on port 8001 (assigned to channel 0) and 8002 (assigned to channel 2) ==== AX.25 Configuration Files ==== The config files are all in ''/etc/ax25''. Here is what I set up for the three key files: === axports === This file sets up two AX.25 ports, one for VHF and one for HF VHF M0GZP-1 19200 255 4 144.375 Mhz 1k2bps HF M0GZP-2 19200 200 4 HF 300bps === nrports === This file sets up a NET/ROM port aliased as GZPNOD nrvhf M0GZP-5 GZPVHF 235 VHF NET/ROM Port nrhf M0GZP-6 GZPHF 40 HF NET/ROM Port NOTE: nrports cannot contain any blank lines. === nrbroadcast === This file configures how our AX.25 ports will broadcast NET/ROM nodes. My VHF node sets all seen nodes to a default quality of 220, and will broadcast any node with a minimum quality of 200. The HF node on the other hand sets all nodes to a default quality of 200 (so as not to advertise HF nodes over VHF), and will broadcast nodes with a minimum quality of 200. VHF 5 200 200 1 HF 5 220 200 1 === ax25d.conf === This file configures the ax25 userspace daemon, which determines what processes are run when other users connect in to the node. In my example, I am calling the program uronode (by N1URO, sadly SK). A separate entry is required for each port. [M0GZP-1 via VHF] NOCALL * * * * * * L default * * * * * * 0 root /usr/local/sbin/uronode uronode [M0GZP-2 via HF] NOCALL * * * * * * L default * * * * * * 0 root /usr/local/sbin/uronode uronode NOCALL * * * * * * L default * * * * * * 0 root /usr/local/sbin/uronode uronode NOCALL * * * * * * L default * * * * * * 0 root /usr/local/sbin/uronode uronode ==== Startup Scripts ==== I wrote some scripts to start everything up. === /usr/sbin/startRadio.sh === This script will: * Create two socat pseudo-tty interfaces, one to each of the network KISS ports * Use ''kissattach'' to attach these interfaces to kernel ax.25 network interfaces * Load the ''netrom'' module and attach it to the port defined in nrports * Run the netrom userspace daemon which handles the netrom broadcasts * Load previous netrom node tables * Run the mheard daemon which keeps track of heard stations * Run the ax25 daemon to support running services #!/bin/bash echo -n Creating socat sockets... socat pty,echo=0,link=/tmp/kiss8001,wait-slave tcp:127.0.0.1:8001 & socat pty,echo=0,link=/tmp/kiss8002,wait-slave tcp:127.0.0.1:8002 & sleep 1 echo Done echo -n Attaching KISS interfaces for direwolf... kissattach -l `ls -l /tmp/kiss8001 | awk '{ print $11 }'` VHF sleep 1 kissattach -l `ls -l /tmp/kiss8002 | awk '{ print $11 }'` HF sleep 1 echo Done echo -n 'Bringing up NET/ROM runtime...' modprobe netrom nrattach nrvhf nrattach nrhf netromd -i -l -d echo -n Restoring node tables... [ -x /etc/ax25/nodesave.sh ] && /etc/ax25/nodesave.sh echo Done echo -n Starting mheard daemon... mheardd -l echo Done echo -n Starting ax25 daemon... ax25d -l echo Done For a modem other than Dire Wolf, an alternative script can be used: #!/bin/bash echo -n Attaching KISS interfaces... kissattach /dev/ttyACM0 HF sleep 1 echo Done echo -n 'Bringing up NET/ROM runtime...' modprobe netrom nrattach netrom netromd -i -l -d echo -n Restoring node tables... [ -x /etc/ax25/nodesave.sh ] && /etc/ax25/nodesave.sh echo Done NB this script appears to run before /dev/ttyACM0 is available, so currently doesn't work. I'm coming up with a fix. === /usr/sbin/stopRadio.sh === This script does the opposite to startRadio, killing the processes and taking down the interfaces #!/bin/bash echo -n Saving node tables... /usr/sbin/nodesave > /etc/ax25/nodesave.sh && chmod 755 /etc/ax25/nodesave.sh echo Done echo -n Killing mheard daemon... killall mheardd sleep 1 echo Done echo -n Killing ax25 daemon... killall ax25d sleep 1 echo Done echo -n Killing all socat processes in case they do not end cleanly... killall socat sleep 1 echo Done echo -n Killing all kissattach processes... killall kissattach sleep 1 echo Done echo -n Killing the netromd process... killall netromd sleep 1 echo Done echo -n Taking down the netrom interface... ifconfig nr0 down sleep 1 echo Done echo -n Removing kernel modules... rmmod netrom && sleep 1 && rmmod mkiss && sleep 1 && rmmod ax25 && sleep 1 echo Done echo -n Taking down the AX.25 interfaces... ifconfig ax0 > /dev/null 2>&1 && ifconfig ax0 down ifconfig ax1 > /dev/null 2>&1 && ifconfig ax1 down sleep 1 echo Done For a modem other than Dire Wolf, an alternative script can be used: #!/bin/bash echo Saving node tables... /usr/sbin/nodesave > /etc/ax25/nodesave.sh && chmod 755 /etc/ax25/nodesave.sh echo Killing all kissattach processes killall kissattach echo Killing the netromd process killall netromd echo Taking down the netrom interface ifconfig nr0 down echo Removing kernel modules rmmod netrom rmmod mkiss rmmod ax25 echo Taking down the AX.25 interfaces ifconfig ax0 > /dev/null 2>&1 && ifconfig ax0 down echo Done Don't forget to make these scripts executable: chmod +x /usr/sbin/startRadio.sh chmod +x /usr/sbin/stopRadio.sh === /lib/systemd/system/ax25.service === This script registers the ax25 service with systemd [Unit] Description=Start up radio processes After=direwolf.service Requires=direwolf.service [Service] Type=oneshot ExecStart=/usr/sbin/startRadio.sh ExecStop=/usr/sbin/stopRadio.sh RemainAfterExit=yes [Install] WantedBy=multi-user.target ==== Time to run ==== To start things up, use systemctl start -- then use status to see how it went: szymon@radio:~ $ sudo systemctl start ax25 szymon@radio:~ $ sudo systemctl status ax25 ● ax25.service - Start up radio processes Loaded: loaded (/lib/systemd/system/ax25.service; disabled; vendor preset: enabled) Active: active (exited) since Mon 2023-04-17 00:36:38 BST; 7s ago Process: 3036 ExecStart=/usr/sbin/startRadio.sh (code=exited, status=0/SUCCESS) Main PID: 3036 (code=exited, status=0/SUCCESS) Tasks: 7 (limit: 4915) CPU: 156ms CGroup: /system.slice/ax25.service ├─3037 socat pty,echo=0,link=/tmp/kiss8001,wait-slave tcp:127.0.0.1:8001 ├─3038 socat pty,echo=0,link=/tmp/kiss8002,wait-slave tcp:127.0.0.1:8002 ├─3047 kissattach -l /dev/pts/4 VHF ├─3061 kissattach -l /dev/pts/3 HF ├─3089 netromd -i -l -d ├─3099 mheardd -l └─3104 ax25d -l Apr 17 00:36:38 radio startRadio.sh[3077]: NET/ROM port nrvhf bound to device nr0 Apr 17 00:36:38 radio startRadio.sh[3082]: NET/ROM port nrhf bound to device nr1 Apr 17 00:36:38 radio netromd[3089]: starting Apr 17 00:36:38 radio startRadio.sh[3036]: Restoring node tables...Done Apr 17 00:36:38 radio mheardd[3099]: starting Apr 17 00:36:38 radio startRadio.sh[3036]: Starting mheard daemon...Done Apr 17 00:36:38 radio startRadio.sh[3036]: Starting ax25 daemon...Done Apr 17 00:36:38 radio systemd[1]: Finished Start up radio processes. Apr 17 00:36:38 radio ax25d[3104]: starting Apr 17 00:36:38 radio ax25d[3104]: new config file loaded successfully szymon@radio:~ $ You will see some new network interfaces on ifconfig (I've removed my normal interfaces): ax0: flags=67 mtu 255 ax25 M0GZP-1 txqueuelen 10 (AMPR AX.25) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 1 bytes 49 (49.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ax1: flags=67 mtu 200 ax25 M0GZP-2 txqueuelen 10 (AMPR AX.25) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 nr0: flags=193 mtu 235 netrom M0GZP-5 txqueuelen 1000 (AMPR NET/ROM) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 nr1: flags=193 mtu 40 netrom M0GZP-6 txqueuelen 1000 (AMPR NET/ROM) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 You can now use ''axcall'' to contact another node, ''axlisten'' to monitor traffic, etc. If it was all successful, enable the service to start at boot: sudo systemctl enable ax25.service