Linux for hamradio

The experimental character of HAM radio matches nicely with the open-source approach of Linux. For many years I used old PCs and laptops running windows to connect to my radios for (contest-)logging, digital modes, and other radio related applications.

A few years ago I’ve bit the bullet and made the switch, using a Raspberry PI running Linux for all software related to my radio hobby. Many good YouTube videos and websites are available describing Linux and Raspberry PIs for hamradio. A few things I had to find out myself, which I will describe on this webpage. As a result this page is not a polished ‘how-to’ document, rather a collection of rough notes I took while making things work.

Applications I use as a minimum

To store data I have a directory on my NAS that is mounted on the RPi, so the SD card in the RPi doesn’t get hammered too hard.

Copy Raspberry Pi image to/from SD card

    [  333.368252] mmc0: new high speed SDXC card at address aaaa
    [  333.369118] mmcblk0: mmc0:aaaa SL64G 59.5 GiB 
    [  333.372686]  mmcblk0: p1 p2
    brw-rw---- 1 root disk 179, 0 Nov 15 15:21 mmcblk0
    brw-rw---- 1 root disk 179, 1 Nov 15 15:21 mmcblk0p1
    brw-rw---- 1 root disk 179, 2 Nov 15 15:21 mmcblk0p2
    /dev/mmcblk0p2 60805892 11939020 45758560 21% /media/berrie/rootfs
    /dev/mmcblk0p1   522232    74038   448194 15% /media/berrie/bootfs
    $ sudo umount /dev/mmcblk0p1
    $ sudo umount /dev/mmcblk0p2
    $ sudo dd if=/dev/mmcblk0 of=/home/berrie/rpi.img bs=4M conv=fsync
    15226+1 records in
    15226+1 records out
    63864569856 bytes (64 GB, 59 GiB) copied, 4297,35 s, 14,9 MB/s
    $ sudo dd of=/dev/mmcblk0 if=/home/berrie/rpi.img bs=4M conv=fsync
    $ losetup -f   # find free loop device
    $ sudo losetup -P /dev/loop0 /home/berrie/rpi.img
    $ losetup -l   # show the used loop devices
    $ sudo mount /dev/loop0p1 /mnt   # you can see /boot in /mnt now.
    $ sudo umount /mnt

    $ sudo mount /dev/loop0p2 /mnt   # you can see / in /mnt now.
    $ sudo umount /mnt
    xz --decompress 2023-10-10-raspios-bookworm-arm64-full.img.xz

Get persistent device pathes to my radios

When multiple radios are connected to the same linux machine, the devices on which these radios become accessable on the linux machine may change on each reboot of the machine. As a consequence your applications that are configured to see a specific radio on a device like /dev/ttyUSBxxx may not work correctly after a reboot, until you have adjusted the configuration. This can be frustratng at times.

When new hardware is added on linux machine, the kernel is notified and passes the information about added/changed/removed hardware to the udev daemon program that always runs. This udev daemon makes changes to /dev to reflect the changes in connected hardware.

The nice thing is that udev uses configuration files that define how hardware changes are reflected in /dev. The website by PA0ROB describes nicely how to configure your radios such that they always show up on the same device.

This worked for me, until I got two very similar radios (a Yaesu FT991 and FTDX10). At that time, the udev scripts could not longer see the difference to show these radios as /dev/FT991 and /dev/FTDX10. After a lot of reading and debuging I was able to make things work, using the following configuration files, where the serial number of the USB interface is used to distinguish the radios.

Regular and stable udev configuration files are stored in the /usr/lib/udev/rules.d directory. Configuration files for Udev that are user made, or modified are recommended to be stored in /etc/udev/rules.

udev config for my FT817

$ cat 99-ft817.rules 
# FT-817 pl2303 UART Bridge
# by PA0ROB (
SUBSYSTEM=="tty", DRIVERS=="ftdi_sio", ATTRS{interface}=="USB Interface III", SYMLINK+="FT817"

udev config for my FT950

This radio is replaced by an FTDX10 in my shack, but I’ll leave the configuration file here for historic lookup.

$ cat 99-ft950.rules 
# FT-950 ftdi UART Bridge
# by PA0ROB (
SUBSYSTEM=="tty", DRIVERS=="ftdi_sio", ATTRS{interface}=="USB HS SERIAL CONVERTER*", SYMLINK+="FT950"

udev config for my FT991

$ cat 99-ft991.rules 
# FT-991(A) CP210x UART Bridge
# by PA0ROB (
SUBSYSTEM=="tty", DRIVERS=="cp210x", ATTRS{interface}=="Standard*", ENV{ID_SERIAL_SHORT}=="AH057M5N221120", SYMLINK+="FT991s"
SUBSYSTEM=="tty", DRIVERS=="cp210x", ATTRS{interface}=="Enhanced*", ENV{ID_SERIAL_SHORT}=="AH057M5N221120", SYMLINK+="FT991e"

udev config for my FTDX10

$ cat 99-ftdx10.rules 
# FTDX10 CP210x UART Bridge
SUBSYSTEM=="tty", DRIVERS=="cp210x", ATTRS{interface}=="Standard*", ENV{ID_SERIAL_SHORT}=="016F14DD", SYMLINK+="FTDX10s"
SUBSYSTEM=="tty", DRIVERS=="cp210x", ATTRS{interface}=="Enhanced*", ENV{ID_SERIAL_SHORT}=="016F14DD", SYMLINK+="FTDX10e"

Access to radios through hamlib

To have a unified access to a wide range of radios, hamlib is a very helpful library/tool. It provides a library that existing applications can link to for accessing radios. And besides it provides a daemon (rigctld) that runs on its own. In the latter case many different applications can access a radio at the same time by connecting/communicating to the radio via the daemon on a configured network port (port 4532 by default).

As the latest radios may not always be properly supported in the default hamlib provided with your flavor of linux, I typically build my own hamlib tooling from sources. This requires a number of packages to be installed as a pre-requisite on a Raspberry Pi:

    $ sudo apt install autotools-dev autoconf automake libtool m4

To get the latest hamlib sources, I use git to manage this:

    $ git clone

    $ git remote -v
    origin (fetch)
    origin (push)

    $ git status
    On branch Hamlib-4.5.6
    Your branch is up to date with 'origin/Hamlib-4.5.6'.

To build hamlib on my machine, I use the following sequence of commands, which installs hamlib in the /usr/local directories:

    $ cd hamlib
    $ ./bootstrap
    $ ./configure
    $ make
    $ sudo make install
    $ sudo ldconfig

To access my radios from the linux command line a few shell scripts have been made like freq, which is included below. These tools use the command line variable RADIO to define what radio to perform the action on.

Note that this tool uses the rigctld daemon when it is running, and the rigctl command otherwise.

# get frequency from given transceiver:
#  ft817  ft950  ft991
if [ -n "$RADIO" ]
    case $RADIO in
    ft817)  rig="ft817" ;;
    ft950)  rig="ft950" ;;
    ft991)  rig="ft991" ;;
    ftdx10) rig="ftdx10" ;;
    *)  echo "Unknown rig"
        exit 1
echo "RIG is $rig"

case $rig in
    OPTS="-C stop_bits=2 -C dtr_state=ON"
    OPTS="-C data_bits=8 -C stop_bits=2 -C serial_parity=None"
    OPTS="$OPTS -C serial_handshake=None -C dtr_state=OFF"
    OPTS="$OPTS -C rts_state=OFF"
*)  echo "Unknown rig in this shack" 2>&1
    exit 1

pid=$(ps -ef | grep bin/rigctld | grep -v grep | awk '{print $2}')

if [ -z "$pid" ]
    freq=$(/usr/local/bin/rigctl -m $RIG -r $DEV -s $SPEED $OPTS f)
    echo "Hamlib daemon running (pid is $pid)"
    freq=$(echo "f" | netcat -N localhost 4532)
echo "Frequency: $freq"
exit 0


Try Left Foot - is what tlf is an acronym for, as Rein PA0R once explained. This curses based tool may not present to nicest GUI, but it has proven to be a reliable tool for CW and SSB contesting.

To get the latest tlf sources, I use git to manage this:

    $ git clone

    $ git remote -v
    origin  git:// (fetch)
    origin  git:// (push)

    $ git status
    On branch master
    Your branch is up to date with 'origin/master'.

To build and install tlf I use to following sequence of commands:

    autoreconf --install
    make install


    sudo apt install taskwarrior

    cd packages/taskopen
    make PREFIX=/usr/local
    make PREFIX=/usr/local install
    sudo cpan



The current versions of Raspbian OS seem to have up to date versions of CQRLOG available, so I have not been building this my self, recently.

    sudo apt install cqrlog

To copy the cqrlog configuration from another machine, to your current machine, this directory needs to be copied: $HOME/.config/cqrlog