axcall vs ax25_call
axcall is the standard program for making outgoing AX.25 connections on Linux. It’s part of the
ax25-apps package on Debian and has a full-screen TUI. When you press enter at the end of a line it automatically converts the line feed to a single carriage return character, as is generally expected by packet radio nodes. It supports all the features you would want when communicating with a BBS, like file transfers and logging.
# radio port, destination callsign axcall vhf VK7AAA-1
ax25_call is a much simpler program which operates more like the
nc command. Installed with the
ax25-tools package, it’s part of a collection of lightweight tools for making outgoing connections that also includes
tcp_call. It prints out a couple of status messages while connecting, then passes data back and forth without any translation of line endings. This means if you connect to a normal packet station from a Linux shell, all output appears on a single line that keeps overwriting itself, which is not normally very useful. It wasn’t meant to be used that way.
# radio port, my callsign, destination callsign ax25_call vhf VK7NTK-1 VK7AAA-1
According to the documentation, the
*_call suite of tools were designed to be used within other programs like
node, making it easy to redirect callers to other systems via a range of protocols. It’s logical that this task was split out into separate binaries since it could be used in a range of applications. Being “glue” in the middle, it also makes sense that the line endings are not mangled because it’s probably already been done by
axcall further up the chain. It’s clear that it was always intended to be used within a CR-line-ending environment because its own status messages like
*** Connected are all terminated with CRs.
One situation where
ax25_call is very useful is when the remote station is not a normal packet radio node. If you run a normal Linux program via
ax25d, it’s still expecting to send and receive line feeds. For example, this
ax25d.conf will dump the connecting station into a Bourne shell running as user
[VK7NTK-1 via vhf] default * * * * * * * guest /bin/sh sh
You can connect using
axcall if you want, but since it sends a CR at the end of each line instead of the expected LF, commands never get executed. In this situation, substituting
ax25_call is a quick and easy workaround.
ax25_call work with normal stations
Depending on your preferences or the type of node you’re communicating with, you may not like how
axcall separates the input and output into their own parts of the screen.
ax25_call is more like the
telnet of old, scrolling inexorably upward and intermingling your input with the output.
Linux has utilities for switching between line endings,
unix2dos. With the
-c mac option it will perform conversions between LF and CR, which is what we want for packet radio.
You might think that you could filter your keyboard input on the way in, and the received messages on the way out:
# Doesn't quite work unix2dos -c mac | ax25_call vhf VK7NTK-1 VK7HDM-9 | dos2unix -c mac
If you run this command, it gets you halfway there. The output is now split into multiple lines:
Connecting to VK7HDM-9 ... *** Connected [FBB-7.0.8-AB1FHMRX$] VK7HDM BBS, Hobart.
There are two problems. Firstly, input doesn’t work. You can press enter as many times as you like but nothing gets transmitted. Secondly, the output is always “one line behind”—you need to receive the next line before it prints the previous one.
These problems are due to buffering in stdin/stdout. Glibc is hard-coded to use LF characters when performing line-based buffering. To avoid waking up programs unnecessarily with incomplete input, by default it buffers content until it sees a LF. Fortunately, there is a wrapper program called
stdbuf that lets you turn off buffering for stdin and stdout for another program.
# This actually works. It's an AX.25 connection but it looks and feels like using nc. stdbuf -i0 -o0 unix2dos -c mac | ax25_call vhf VK7NTK-1 VK7HDM-9 | stdbuf -i0 -o0 dos2unix -c mac
Putting this inside a convenient shell script or alias is left as an exercise to the reader.
Line conversion for a UNIX program in ax25d?
What about the opposite? Can I use these sorts of tricks to make it so that a remote station can connect with
axcall (or an old-school TNC)? I want to somehow handle that connection with a Linux program through
ax25d, while automatically translating their CRs into LFs and vice versa. As it turns out, this is basically possible.
[VK7NTK-1 via vhf] default * * * * * * * guest /usr/bin/stdbuf stdbuf -o0 script -q -c /bin/bash /dev/null
This isn’t actually quite right. I’m still getting CRLFs coming back for each line which means that
axcall shows a blank line between each line of output. My attempts to fix this introduced a new problem—if you do an unbuffered
write() for every character, the radio will transmit a separate packet for every character, which is of course extremely slow.
Really the right solution here would be to write a wrapper binary that carefully manages its input and output buffering, handles line ending conversion, and consolidates writes to avoid wasting packets. This is mostly pointless and I don’t think I’m ever going to do this. I’m going to leave these notes here for anyone who’s motivated enough to try.