Category Archives: ham radio

AA6KJ ham radio blog

Bandmaster V info widget

Wrote the following info widget for Bandmaster V (Linux):

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <qt6/libqt6c.h>

// Define the antenna names
#define ANTENNA1 "6m beam"
#define ANTENNA2 "WARC beam"
#define ANTENNA3 "Stack"
#define ANTENNA4 "40m beam"
#define ANTENNA5 "No antenna"
#define ANTENNA6 "No antenna"
#define ANTENNA7 "No antenna"
#define ANTENNA8 "No antenna"
#define ANTENNA9 "No antenna"
#define ANTENNA10 "No antenna"
#define ANTENNA11 "No antenna"
#define ANTENNA12 "No antenna"

#define DEVICE "/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_B003ISA1-if00-port0"

int fd;
void *widget, *label;

int read_untilcr(int fd, char *buf, int maxlen) {

int pos = 0, bytes_rd;

while(1) {
if((bytes_rd = read(fd, buf + pos, 1)) < 0) return -1;
if(bytes_rd == 0) {
sleep(1); // could be less than 1sec
continue;
}
if(!pos && (*buf == '\r' || *buf == '\n')) continue;
if(pos == maxlen) return -1;
if(buf[pos] == '\r') break;
pos++;
}
buf[pos] = '\0';
return pos;
}

void set_tty() {

struct termios param;

if(tcgetattr(fd, &param) < 0) {
fprintf(stderr, "Status get failed.\n");
exit(1);
}

param.c_cflag &= ~PARENB;
param.c_cflag &= ~CSTOPB;
param.c_cflag |= CS8;
param.c_cflag &= ~CRTSCTS;
param.c_cflag |= CREAD | CLOCAL;
param.c_lflag &= ~ICANON;
param.c_lflag &= ~ECHO;
param.c_lflag &= ~ECHOE;
param.c_lflag &= ~ECHONL;
param.c_lflag &= ~ISIG;
param.c_iflag &= ~(IXON | IXOFF | IXANY);
param.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
param.c_oflag &= ~OPOST;
param.c_oflag &= ~ONLCR;
cfsetispeed(&param, B57600);
cfsetospeed(&param, B57600);

if(tcsetattr(fd, TCSANOW, &param) < 0) {
fprintf(stderr, "Status set failed.\n");
exit(1);
}
}

char *txt_noant = "<b><font color='red'>No antenna.</font></b>",
*txt_40m = "<b><font color='blue'>40m beam.</font></b>",
*txt_warc = "<b><font color='blue'>WARC beam.</font></b>",
*txt_stack = "<b><font color='blue'>Stack.</font></b>",
*txt_6m = "<b><font color='blue'>6m beam.</font></b>";

void update_band_info(void *asd) {

int len, antenna, relay;
char buf[512];

if((len = read_untilcr(fd, buf, sizeof(buf))) < 0) {
fprintf(stderr, "Read error.\n");
exit(1);
}
if(sscanf(buf, "[TC4RFA29H00M0%1d01EEEEEEEEEEEE%4d]", &antenna, &relay) != 2) return; // Some other mesg

switch(antenna) {
case 1:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA1, relay);
q_label_set_text(label, buf);
break;
case 2:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA2, relay);
q_label_set_text(label, buf);
break;
case 3:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA3, relay);
q_label_set_text(label, buf);
break;
case 4:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA4, relay);
q_label_set_text(label, buf);
break;
case 5:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA5, relay);
q_label_set_text(label, buf);
break;
case 6:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA6, relay);
q_label_set_text(label, buf);
break;
case 7:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA7, relay);
q_label_set_text(label, buf);
break;
case 8:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA8, relay);
q_label_set_text(label, buf);
break;
case 9:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA9, relay);
q_label_set_text(label, buf);
break;
case 10:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA10, relay);
q_label_set_text(label, buf);
break;
case 11:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA11, relay);
q_label_set_text(label, buf);
break;
case 12:
sprintf(buf, "<b><font color='blue'>%s (%d)</font></b>", ANTENNA12, relay);
q_label_set_text(label, buf);
break;
default:
q_label_set_text(label, "<b><font color='red'>Unknown antennan.</font></b>");
}
}

int main(int argc, char *argv[]) {

QApplication *app;
QTimer *timer;

if((fd = open(DEVICE, O_RDONLY)) < 0) {
fprintf(stderr, "Can't open device.\n");
exit(1);
}
set_tty();

app = q_application_new(&argc, argv);
widget = q_widget_new2();
timer = q_timer_new2(widget);
q_widget_set_window_title(widget, "Antenna selection");
q_widget_resize(widget, 150, 30);
label = q_label_new5("------------------------------", widget);
q_label_set_alignment(label, QT_ALIGNMENTFLAG_ALIGNCENTER);
q_label_set_text_format(label, QT_TEXTFORMAT_RICHTEXT);
q_timer_start(timer, 100);
q_timer_on_timeout(timer, update_band_info);
q_widget_show(widget);
(void) q_application_exec();
q_widget_delete(widget);
q_application_delete(app);

close(fd);
}

Uses libqt6c (QT bindings for C).

Tower and antenna installation

Some photos from the project.

Time to get started!

Sections of Rohn-55g on the ground.

Bearing installation on the tower (left to right: Dale, K5ZXH; Matt, KC1XX; Jussi, AA6KJ).

Theodore inspecting the foundation and the rotor

The first piece of Rohn-55g on the rotor

All 140′ of Rohn-55g up!

Antennas going up!

All done!

Final rotor setup.

CQ WW DX Contest CW 2025

I worked 15m single band (high power, unassisted); about 30 hours. Some issues during the contest:

  • 5 hour power outage on Sunday morning. Of course, there was a great EU opening during that time! G E N E R A T O R next time…
  • hamlib/rigctld keying problems that required frequent restarting of both not1mm and rigctld. Switching to cwdaemon for the next contest.
  • It was cold in the shack! I need to work on the insulation!

But still the contest went much better than last year (… new antennas …): 1344 QSOs, 122 countries, and 35 zones.

Ham radio on Linux

The following software works great (on Arch Linux):

  • General logging: qlog which can be found from both AUR and Flatpak
  • Digital modes: WSJT-X_improved from AUR
  • Contesting: not1mm. I recommend using cwdaemon for generating CW rather than CAT with rigctld. The latter is buggy and can crash frequently. Install using the uv system (python).

The new tower works great!

145′ Rotating Rohn 55 tower (tower hardware & installation KC1XX

Antennas:

Improve timing of cwdaemon on Linux

If one starts cwdaemon directly on Linux, it produces rather choppy and poor CW. So, I experimented a bit and it seems that the following will produce nice and consistent CW:

# echo 1 > /sys/bus/usb-serial/devices/ttyUSB1/latency_timer
# chrt -f 99 /usr/bin/cwdaemon -d /dev/ttyUSB1 -o key=DTR -o ptt=none -x n

This reduces the rs232 port latency (1st line; 1 ms latency), runs cwdaemon with real time priority (chrt command) and disables audio output on the computer (-x n). In my case above /dev/ttyUSB1 is the RS232 port for the radio, which uses DTR signal for keying.

Once can put the above in a bash script so cwdaemon can be started easily.