Friday 25 January 2019

The APRS iGate

While working on TT7B, I found a need to do long term tests of the GPS module, the temperature and pressure sensors, and overall tracker operation. These were typically carried out by transmitting APRS packets with the desired information. The need to run the SDR software to receive the packets, though, kept taking its toll on my PC's performance, so eventually I began contemplating offloading the reception to something dedicated to the task. The solution I liked the most constituted running the software defined radio and the respective demodulating/decoding software on a Raspberry Pi.
The model I opted for was the smallest and least power hungry board from the family - the Raspberry Pi Zero W. It was crucial to choose the W version, which came with in-built Wi-Fi and Bluetooth interfaces, because I intended to operate the Pi 'headless'. Meaning without a monitor, mouse, or keyboard, but accessing it remotely via Secure Shell (SSH), or Virtual Network Computing (VNC). On the radio side of things, I utilized the RTL-SDR Blog V.3 dongle that has been part of all my previous receiving setups.
Aside from the Pi, an SD card, the RTL-SDR dongle, and a male micro B to female type A USB adapter cord, I needed only a 5V power source. That introduced two possibilities. Either a portable version supplied by a 5Ah power bank, or a stationary setup fed by a 5V wall adapter. The choice depends on the circumstances of the specific test I intend to do.

I had a basic idea of how this setup was supposed to work from back when I read the Direwolf documentation which included a couple of PDFs detailing running the software on a Raspberry Pi. But a more recent Google search on the topic produced a very neatly done summary of the necessary steps to make the iGate work by Keith G6NHU. In the beginning, I followed his initial post to do the basic installations, but as Raspbian was released in a new version (Stretch) since the time of the writing, the later stages slightly differ. Some of the newer steps are outlined in Keith's follow-up post. Since there are some differences, I will detail the steps I had to do to make my setup work in the following paragraphs.

I started by downloading Raspbian Stretch with desktop and recommended software (1.8GB) released on November 13, 2018 from raspberrypi.org download page. The unzipped file grew to a 5.3GB image which was then flashed using Win32DiskImager (version 0.9) on to the formatted 16GB SD card.

With the SD card still plugged in my PC, I accessed the drive, now called 'boot', with a file manager and created two additional files there which would serve to provide the Pi with necessary information about my local Wi-Fi network and enable SSH access.
country=CZ
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
	ssid="network_name"
	psk="network_password"
	key_mgmt=WPA-PSK
}
The first file was called wpa_supplicant.conf and contained information in the format above. In my case 'country' being 'CZ' for the Wi-Fi frequency bands allocated in the Czech Republic, 'ssid' for the name of my WiFi network, and 'psk' for the password to my network. The second file was empty and called ssh without any extension.

Now for the following instructions, I plugged the SD card in the Raspberry Pi and provided it with a 5V power supply. After the initial boot sequence, the Pi, under the default hostname raspberrypi, showed up in my Wi-Fi router's client list with a newly assigned local IP address, specifically 192.168.0.137. At this point I installed PuTTY (version 0.7) on my PC which is a terminal emulator that can establish an SSH connection between the Pi and a Windows running PC.
After having PuTTY open a connection to the IP address obtained from my router, the Raspberry Pi asked for a default login which was pi and a default password which was raspberry. These defaults should be modified following typing this command in the terminal:
sudo raspi-config
The command brought up a menu that can be seen in the image above where I changed the password, the default hostname (in my case to pizero1), expanded the filesystem on the SD card, in boot options selected Desktop/CLI and then Desktop Autologin, and also enabled VNC in case I wanted to see the Pi's desktop as well instead of just the terminal.

Following that I created a new user which would be used in the remainder of instructions. This also automatically created /home/pizero1/ folder which would contain the upcoming installations and data.
sudo adduser pizero1
To utilize the new user fully, it had to be added to a group of users with superuser access which was done with the following command.
sudo visudo
And adding the following line pizero1 ALL=(ALL) ALL below the original pi user.

Prior to moving on to installing software for the receiver, I updated the currently installed packages to their latest versions since some time had passed since the operating system was released.
sudo apt-get update
sudo apt-get dist-upgrade
This step in the end took quite a while before the Pi downloaded and installed all the packages. About 10-20 minutes.

The Direwolf documentation mentions issues with Pulseaudio and suggests removing it if it is installed.
sudo apt-get remove --purge pulseaudio
sudo apt-get autoremove
rm -rf /home/pi/.pulse

In case the system requires a reboot at any point.
sudo reboot now

Instead of Pulseaudio, Direwolf uses libasound2-dev package.
sudo apt-get install libasound2-dev

The installation of Direwolf itself started with navigating to the user's home directory and cloning the current repository from Github (version 1.5 in my case).
cd ~
git clone https://www.github.com/wb2osz/direwolf
cd ~/direwolf
make
sudo make install
make install-rpi
make install-conf

This was followed by installation of the software for the RTL-SDR dongle.
cd ~
sudo apt-get install cmake build-essential libusb-1.0-0-dev
git clone git://git.osmocom.org/rtl-sdr.git
cd rtl-sdr
mkdir build
cd build
cmake ../ -DINSTALL_UDEV_RULES=ON -DDETACH_KERNEL_DRIVER=ON
make
sudo make install
sudo ldconfig

Now after returning back to the user's home directory.
cd ~
I could see that Direwolf had placed a generic direwolf.conf file there which the running instance bases its behaviour on. For example, if the file specifies a directory or a file for a log, Direwolf saves every decoded packet to a log file. If login, password and server are specified, Direwolf uploads received packets to the Internet database. Since I intended to use the Pi sometimes as an iGate and sometimes just for logging data locally, I made two copies of the original config file and modified them accordingly.
cp direwolf.conf /home/pizero1/dw_offline.conf
cp direwolf.conf /home/pizero1/dw_igate.conf

For the data logging usage, the only two modifications in dw_offline.conf were an added line at the end of the file specifying the directory and file for the packet log, and a line enabling Data Carrier Detect (DCD) signal on the Pi's GPIO21 to blink an LED whenever Direwolf detects a packet.
DCD GPIO 21
LOGFILE /home/pizero1/dw_offline.log

In case of the iGating setup, the modifications in dw_igate.conf consisted of the same additions as previously, but also a few more lines specifying the receiving station's callsign, the European APRS server to upload the packets, and a beacon message of the receiving station itself (both latitude and longitude in the example below belong on the same line). The password for a specific callsign can be obtained at this link. Most of these lines were already present in the config file but commented out.
MYCALL OK9STS
DCD GPIO 21
IGSERVER euro.aprs2.net
IGLOGIN OK9STS 20905
PBEACON sendto=IG delay=0:30 every=60:00 symbol="igate" overlay=R lat=49^28.14N long=018^09.05E
LOGFILE /home/pizero1/dw_igate.log

To allow the DCD blinking LED functionality, the user has to be a part of gpio group, so Direwolf is granted access to the Pi's pins.
sudo adduser pizero1 gpio

The idea behind this setup is that whenever the Pi is powered up, it boots up and automatically runs the receiving software, so it can start demodulating and decoding packets without any intervention from the user. To achieve this, I had to setup a systemd service for rtl_fm and Direwolf. The original description of this approach comes from this post by Josh VK2HFF. I started by creating a file with the following contents.
sudo nano /etc/systemd/system/direwolf.service
[Unit]
Description=Direwolf service
After=sound.target

[Service]
User=root
ExecStart=/usr/local/bin/dw.sh
Restart=always

[Install]
WantedBy=multi-user.target
DefaultInstance=1
After that I created another file, which was the process the service starts in ExecStart, with the following contents.
sudo nano /usr/local/bin/dw.sh
#!/bin/sh
PATH=/bin:/usr/bin:/usr/local/bin
unset LANG
rtl_fm -f 144.80M - | direwolf -c /home/pizero1/dw_igate.conf -r 24000 -D 1 -
The process is a shell script with a command to run the demodulator rtl_fm at a center frequency of 144.8MHz and pipe the output to the decoder's input - Direwolf. In this case, Direwolf uses the dw_igate.conf file to set up its behaviour. Also the script file had to be made executable.
sudo chmod +x /usr/local/bin/dw.sh

At this point, all that remained was to enable the service to always start at boot.
sudo systemctl enable direwolf
Starting at boot can also be disabled by:
sudo systemctl disable direwolf
Or to immediately start or stop the enabled service:
sudo systemctl start direwolf
sudo systemctl stop direwolf
Status of the service along with the latest output can be displayed by typing:
sudo systemctl status direwolf
There is also the possibility to view Direwolf's live output in the terminal by typing:
sudo journalctl -o cat -af -u direwolf
Here is the station shown on aprs.fi, and the uploaded raw packets can be found there as well. The transmitter in this case doesn't show up on the map, because it didn't send its position. This all for the iGating setup. The remaining paragraphs focus on data logging.

The data logging setup without uploading the packets to the Internet required a few more steps. First, I switched the config file based on which Direwolf sets itself up.
sudo nano /usr/local/bin/dw.sh
rtl_fm -f 144.80M - | direwolf -c /home/pizero1/dw_offline.conf -r 24000 -D 1 -
Back when I ran RTL-SDR and Direwolf on my PC, I had trouble with Direwolf's inbuilt packet logging occasionally dropping characters in my non-standard packets. I solved that by using kissutil.exe, normally distributed with Direwolf, which used to save each raw packet in a separate file on the disk. For the Raspberry Pi, however, I decided to write my own script that would connect to the Direwolf's KISS output instead of kissutil, and would store and parse the raw packets in a way I wanted.

Kiss.py simply connects to localhost at port 8001 which is opened by Direwolf, and which is where Direwolf communicates via the KISS protocol. The script simply waits for data sent by Direwolf which when Direwolf successfully decodes are the raw packets, then parses the data, attaches a timestamp, and saves the result on a new line in kiss.log. The script can be found here.

First, I copied the written python script to the Raspberry Pi. Since I was on a Windows PC, I had to use pscp.exe which comes with PuTTY. In Windows command line, I navigated to the directory where kiss.py was storred and ran the following command:
"C:\Program Files\PuTTY\pscp.exe" kiss.py pizero1@192.168.0.137:
After logging into the Pi again, I made the python script, which was now in the user's home directory, executable.
sudo chmod +x kiss.py
The other thing I had to do to make this work was modifying dw.sh to run the python script as well.
sudo nano /usr/local/bin/dw.sh
#!/bin/sh
PATH=/bin:/usr/bin:/usr/local/bin
unset LANG
sleep 5 && python /home/pizero1/kiss.py &
rtl_fm -f 144.80M - | direwolf -c /home/pizero1/dw_offline.conf -r 24000 -D 1 -
This way the script executes the 5s sleep command followed by running kiss.py in parallel to rtl_fm and Direwolf. The 5s period is there to allow Direwolf to start and open the 8001 port first.
The result can be seen in the screengrabs above. On the left, the original log file produced by Direwolf upon receiving some packets. And on the right, kiss.log with the formatted packets created by kiss.py.

To copy the log file to PC, or any other file for that matter, I again used PuTTY from the Windows command line:
"C:\Program Files\PuTTY\pscp.exe" pizero1@192.168.0.137:kiss.log F:\
And to delete an old log file from the Pi's terminal:
rm /home/pizero1/kiss.log
Since the primary purpose behind building the iGate was local data logging and testing, I didn't really bother with setting it up properly as one would in case of a permanent installation serving the whole area. It rather usually sits somewhere nearby a wall power socket with a simple wire in place of an antenna which is perfectly sufficient for the intended task.

I also added an LED with a 330Ω resistor between the Pi's GPIO21 and ground to utilize the Direwolf's Data Carrier Detect (DCD) signal to blink whenever there is a received packet. A quick check that the transmitter still works especially useful in multiple day testing.

When idle with the demodulating/decoding software shut down, the consumption of the setup was 174mA (0.87W) compared to a stand-alone Raspberry Pi's 110mA (0.55W). When receiving, the consumption rose to around 450mA (2.25W) with minima at 412mA (2.06W) and maxima at 503mA (2.52W). The boot time was typically around 70s.

No comments:

Post a Comment