Merge pull request #55 from thetechprepper/feature/fldigi

Merge updated feature/fldigi branch to R5. Initial attempt at full plug-and-play support.
This commit is contained in:
thetechprepper
2025-10-02 14:48:49 -07:00
committed by GitHub
14 changed files with 4005 additions and 4 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ Miles=true
MyCall=N0CALL
MyGrid=DM33
MyGroups=@@TTP,@@TTPNET
MyInfo=ETC R3
MyInfo=ETC R5
Polling=1
PSKReporter=false
PTTMethod=@Variant(\0\0\0\x7f\0\0\0\x1eTransceiverFactory::PTTMethod\0\0\0\0\xfPTT_method_CAT\0)
File diff suppressed because it is too large Load Diff
+201
View File
@@ -0,0 +1,201 @@
#!/bin/bash
#
# Author : Gaston Gonzalez
# Date : 2 October 2025
# Purpose : Wrapper script for starting fldigi with PnP support
#
# Preconditions
# 1. Supported radio and audio interface are connected and properly detected
#
# Postconditions
# 1. Stop all running EmComm Tools modes
# 2. fldigi core settings updated (e.g., CAT, audio, user config and ETC defaults)
# 3. fldigi started
usage() {
echo "usage: $(basename $0) <command>"
echo " start - Update config and start fldigi"
echo " update-config - Update config"
}
if [[ $# -ne 1 ]]; then
usage
exit 1
fi
notify_user() {
notify-send \
-t 5000 \
--app-name="EmComm Tools" \
"$1"
}
start() {
/opt/emcomm-tools/bin/et-kill-all && update-config && /usr/local/bin/fldigi &
}
update-config () {
# 1. Check if the audio device symlink was created by the udev rules
if [[ -e /dev/et-audio ]]; then
# 2. Check that this device was properly tagged with the ET_AUDIO env variable
APLAY_OUT=$(arecord -l | grep ET_AUDIO)
if [[ $? -eq 0 ]]; then
## Configure ALSA settings for sound card
/opt/emcomm-tools/bin/et-audio update-config
else
et-log "No ET_AUDIO device detected."
notify_user "Can't start fldigi. No ET_AUDIO device detected."
exit 1
fi
else
et-log "No ET_AUDIO device plugged in."
notify_user "Can't start fldigi. No supported audio device plugged in."
exit 1
fi
PORT_AUDIO_CONF=/tmp/conf.tmp
GEO_CONF=/tmp/geo.tmp
FLDIGI_CONF_DIR="${HOME}/.fldigi"
FLDIGI_CONF_FILE="${FLDIGI_CONF_DIR}/fldigi_def.xml"
if [[ ! -e ${FLDIGI_CONF_DIR} ]]; then
et-log "${FLDIGI_CONF_DIR} does not exist. Creating it from template."
mkdir -v ${FLDIGI_CONF_DIR}
cp -v /etc/skel/.fldigi/fldigi_def.xml ${FLDIGI_CONF_DIR}
fi
[ -z "$ET_USER_CONFIG" ] && ET_USER_CONFIG="${HOME}/.config/emcomm-tools/user.json"
# clean up temporary config that may exist
[[ -e ${PORT_AUDIO_CONF} ]] && rm ${PORT_AUDIO_CONF}
et-portaudio 2>/dev/null > ${PORT_AUDIO_CONF}
if [[ $? -ne 0 ]]; then
echo "No supported ET_AUDIO device found"
exit 1
fi
DEVICE=$(jq -r -e '.device' ${PORT_AUDIO_CONF})
if [[ $? -ne 0 ]]; then
echo "Error getting PulseAudio device name for ET_AUDIO device"
exit 1
fi
INDEX=$(jq -r -e '.index' ${PORT_AUDIO_CONF})
if [[ $? -ne 0 ]]; then
echo "Error getting PulseAudio device index for ET_AUDIO device"
exit 1
fi
##############################################
# Map ALSA ET_AUDIO device to PortAudio device
##############################################
et-log "Updating PortAudio device configuration..."
sed -i "s|^<AUDIOIO>.*|<AUDIOIO>1</AUDIOIO>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTINDEVICE>.*|<PORTINDEVICE>${DEVICE}</PORTINDEVICE>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTININDEX>.*|<PORTININDEX>${INDEX}</PORTININDEX>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTOUTDEVICE>.*|<PORTOUTDEVICE>${DEVICE}</PORTOUTDEVICE>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTOUTINDEX>.*|<PORTOUTINDEX>${INDEX}</PORTOUTINDEX>|" ${FLDIGI_CONF_FILE}
et-log "Using device '${DEVICE}' and device index '${INDEX}' for PortAudio configuration"
#################
# Update callsign
#################
et-log "Updating callsign configuration..."
CALLSIGN=$(jq -r -e '.callsign' ${ET_USER_CONFIG})
if [[ "${CALLSIGN}" = "N0CALL" ]]; then
et-log "Exiting early. No callsign set. Run: et-user."
exit 1
fi
et-log "Using callsign '${CALLSIGN}'"
sed -i "s|^<MYCALL>.*|<MYCALL>${CALLSIGN}</MYCALL>|" ${FLDIGI_CONF_FILE}
###############################################
# Update grid based on ETC geolocation services
###############################################
et-log "Updating your grid square..."
curl -f -s "http://localhost:1981/api/geo/position" > ${GEO_CONF}
if [[ $? -eq 0 ]]; then
GRID=$(jq -r -e '.position.gridSquare' ${GEO_CONF})
if [[ $? -eq 0 ]]; then
et-log "Using grid square '${GRID}' for your location"
sed -i "s|^<MYLOC>.*|<MYLOC>${GRID}</MYLOC>|" ${FLDIGI_CONF_FILE}
fi
fi
[[ -e ${GEO_CONF} ]] && rm ${GEO_CONF}
#####################################################################
# Configure CAT interface using Hamlib's rig control daemon (rigctld)
#####################################################################
et-log "Updating CAT control configuration..."
sed -i "s|^<CHKUSEHAMLIBIS>.*|<CHKUSEHAMLIBIS>1</CHKUSEHAMLIBIS>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<HAMRIGMODEL>.*|<HAMRIGMODEL>2</HAMRIGMODEL>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<HAMLIBCMDPTT>.*|<HAMLIBCMDPTT>1</HAMLIBCMDPTT>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<HAMRIGDEVICE>.*|<HAMRIGDEVICE>localhost:4532</HAMRIGDEVICE>|" ${FLDIGI_CONF_FILE}
######################################
# Enable Reed Soloman ID for RX and TX
######################################
et-log "Enabling Reed Soloman ID for RX/TX..."
sed -i "s|^<RECEIVERSID>.*|<RECEIVERSID>1</RECEIVERSID>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<TRANSMITRSID>.*|<TRANSMITRSID>1</TRANSMITRSID>|" ${FLDIGI_CONF_FILE}
###########################
# Modem configuration: MT63
###########################
et-log "Updating MT63 modem configuration..."
sed -i "s|^<MT63INTEGRATION>.*|<MT63INTEGRATION>1</MT63INTEGRATION>|" ${FLDIGI_CONF_FILE}
########################
# Repeater configuration
########################
et-log "Updating settings for linked repeater systems..."
# Key up for 2 seconds before transmitting tone. Needed for linked repeater systems.
sed -i "s|^<PRETONE>.*|<PRETONE>2</PRETONE>|" ${FLDIGI_CONF_FILE}
#####################
# NBEMS configuration
#####################
et-log "Updating settings for NBEMS..."
sed -i "s|^<OPEN_NBEMS_FOLDER>.*|<OPEN_NBEMS_FOLDER>1</OPEN_NBEMS_FOLDER>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<FLMSG_PATHNAME>.*|<FLMSG_PATHNAME>/usr/local/bin/flmsg</FLMSG_PATHNAME>|" ${FLDIGI_CONF_FILE}
}
case $1 in
start)
start
;;
update-config)
update-config
;;
*)
echo "Invalid command."
usage
exit 1
;;
esac
+5 -1
View File
@@ -2,7 +2,7 @@
#
# Author : Gaston Gonzalez
# Date : 12 November 2024
# Updated : 7 February 2025
# Updated : 2 October 2025
# Purpose : Stops all EmComm Tools sound-based services (i.e. modems) and
# amatuer radio applications to ensure a clean start for the next mode.
@@ -33,6 +33,10 @@ stop_all_services() {
pkill et-vara
pkill VARA
# Stop fldigi
pkill fldigi
pkill et-fldigi
stop_pat
}
@@ -12,7 +12,7 @@ show-desktop-icons = false
picture-uri = 'file:///usr/share/backgrounds/emcomm-tools-wallpaper.png'
[org.gnome.shell]
favorite-apps = ['emcomm-tools.desktop', 'js8call.desktop', 'et-aircraft.desktop', 'org.gnome.Terminal.desktop', 'navit.desktop', 'min.desktop', 'org.gnome.Nautilus.desktop']
favorite-apps = ['emcomm-tools.desktop', 'js8call.desktop', 'fldigi.desktop', 'et-aircraft.desktop', 'org.gnome.Terminal.desktop', 'navit.desktop', 'min.desktop', 'org.gnome.Nautilus.desktop']
last-selected-power-profile = 'performance'
[org.gnome.system.location]
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
# Author : Gaston Gonzalez
# Date : 2 October 2025
# Purpose : Builds and installs et-portaudio
set -e
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
trap 'et-log "\"${last_command}\" command failed with exit code $?."' ERR
. ./env.sh
APP="et-portaudio"
VERSION="1.0.0"
APP_AND_VERSION="${APP}-${VERSION}"
INSTALL_DIR="/opt/${APP_AND_VERSION}"
LINK_PATH="/opt/${APP}"
et-log "Installing ${APP} ${VERSION}"
CWD_DIR=`pwd`
cd ../src/et-portaudio
# Compile
make install
[[ -e ${LINK_PATH} ]] && rm ${LINK_PATH}
ln -v -s ${INSTALL_DIR} ${LINK_PATH}
stow -v -d /opt ${APP} -t /usr/local
cd ${CWD}
+4
View File
@@ -1,6 +1,7 @@
#!/bin/bash
# Author : Gaston Gonzalez
# Date : 17 September 2025
# Updated : 2 October 2025
# Purpose : Builds and installs fldigi
set -e
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
@@ -36,6 +37,9 @@ make
# Install
make install
# Use wrapper script as launcher executable
sed -i 's|^Exec.*|Exec=/opt/emcomm-tools/bin/et-fldigi start|' /opt/fldigi/share/applications/fldigi.desktop
[[ -e ${LINK_PATH} ]] && rm ${LINK_PATH}
ln -v -s ${INSTALL_DIR} ${LINK_PATH}
+3 -1
View File
@@ -2,7 +2,7 @@
#
# Author : Gaston Gonzalez
# Date : 16 March 2024
# Updated : 30 September 2025
# Updated : 2 October 2025
# Purpose : Main installer for EmComm Tools Community (ETC)
. ./env.sh
@@ -90,4 +90,6 @@ exitIfNotRoot
# Install fldigi suite
./install-fldigi.sh
./install-et-portaudio.sh
# TODO: add installers for flmsg and flamp
+2
View File
@@ -0,0 +1,2 @@
et-portaudio
*.o
+25
View File
@@ -0,0 +1,25 @@
CC = gcc
CFLAGS = -Wall -O2
LDFLAGS = -lportaudio -lasound
TARGET = et-portaudio
SRC = main.c
VERSION=1.0.0
INSTALL_DIR = /opt/et-portaudio-$(VERSION)/bin
.PHONY: install
all: $(TARGET)
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS)
install: $(TARGET)
@echo "Installing $(TARGET) to $(INSTALL_DIR)..."
@mkdir -p $(INSTALL_DIR)
@cp $(TARGET) $(INSTALL_DIR)/
@chmod 755 $(INSTALL_DIR)/$(TARGET)
@echo "Done."
clean:
rm -f $(TARGET) *.o
+32
View File
@@ -0,0 +1,32 @@
# et-portaudio
A utility program intended for script use to convert a supported
EmComm Tools ALSA audio device (i.e. `ET_AUDIO`) to a PulseAudio device.
## Usage
Returns a JSON object with the PulseAudio device details on success.
```bash
./et-portaudio 2>/dev/null
{
"device": "USB Audio Device: - (hw:1,0)",
"index": 6
}
```
If no supported device is found or on error, the utility exits with an
exit status of 1.
## Build
``bash
make
```
## Install
```bash
sudo make install
```
+147
View File
@@ -0,0 +1,147 @@
#!/bin/bash
# Author : Gaston Gonzalez
# Date : 1 October 2025
# Updated : 2 October 2025
# Purpose : Temporary script to fast-fail dynamic fldigi config for PnP
#
# NOTE: THIS IS SCRIPT IS INTENDED FOR DEVELOPMENT OF THE PNP SOLUTION.
CMD=et-portaudio
PORT_AUDIO_CONF=/tmp/conf.tmp
GEO_CONF=/tmp/geo.tmp
FLDIGI_CONF_DIR="${HOME}/.fldigi"
FLDIGI_CONF_FILE="${FLDIGI_CONF_DIR}/fldigi_def.xml"
[ -z "$ET_USER_CONFIG" ] && ET_USER_CONFIG="${HOME}/.config/emcomm-tools/user.json"
# clean up temporary config that may exist
[[ -e ${PORT_AUDIO_CONF} ]] && rm ${PORT_AUDIO_CONF}
[[ ! -e ${CMD} ]] && make
./${CMD} 2>/dev/null > ${PORT_AUDIO_CONF}
if [[ $? -ne 0 ]]; then
echo "No supported ET_AUDIO device found"
exit 1
fi
DEVICE=$(jq -r -e '.device' ${PORT_AUDIO_CONF})
if [[ $? -ne 0 ]]; then
echo "Error getting PulseAudio device name for ET_AUDIO device"
exit 1
fi
INDEX=$(jq -r -e '.index' ${PORT_AUDIO_CONF})
if [[ $? -ne 0 ]]; then
echo "Error getting PulseAudio device index for ET_AUDIO device"
exit 1
fi
################################
# Bootstrap fldigi configuration
################################
et-log "Checking for .fldigi directory"
[[ ! -e ${FLDIGI_CONF_DIR} ]] && mkdir -v ${FLDIGI_CONF_DIR}
et-log "Copying fldigi template..."
cp -v ../../overlay/etc/skel/.fldigi/fldigi_def.xml ~/.fldigi/
##############################################
# Map ALSA ET_AUDIO device to PortAudio device
##############################################
et-log "Updating PortAudio device configuration..."
sed -i "s|^<AUDIOIO>.*|<AUDIOIO>1</AUDIOIO>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTINDEVICE>.*|<PORTINDEVICE>${DEVICE}</PORTINDEVICE>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTININDEX>.*|<PORTININDEX>${INDEX}</PORTININDEX>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTOUTDEVICE>.*|<PORTOUTDEVICE>${DEVICE}</PORTOUTDEVICE>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTOUTINDEX>.*|<PORTOUTINDEX>${INDEX}</PORTOUTINDEX>|" ${FLDIGI_CONF_FILE}
et-log "Using device '${DEVICE}' and device index '${INDEX}' for PortAudio configuration"
#################
# Update callsign
#################
et-log "Updating callsign configuration..."
CALLSIGN=$(jq -r -e '.callsign' ${ET_USER_CONFIG})
if [[ "${CALLSIGN}" = "N0CALL" ]]; then
et-log "Exiting early. No callsign set. Run: et-user."
exit 1
fi
et-log "Using callsign '${CALLSIGN}'"
sed -i "s|^<MYCALL>.*|<MYCALL>${CALLSIGN}</MYCALL>|" ${FLDIGI_CONF_FILE}
###############################################
# Update grid based on ETC geolocation services
###############################################
et-log "Updating your grid square..."
curl -f -s "http://localhost:1981/api/geo/position" > ${GEO_CONF}
if [[ $? -eq 0 ]]; then
GRID=$(jq -r -e '.position.gridSquare' ${GEO_CONF})
if [[ $? -eq 0 ]]; then
et-log "Using grid square '${GRID}' for your location"
sed -i "s|^<MYLOC>.*|<MYLOC>${GRID}</MYLOC>|" ${FLDIGI_CONF_FILE}
fi
fi
[[ -e ${GEO_CONF} ]] && rm ${GEO_CONF}
#####################################################################
# Configure CAT interface using Hamlib's rig control daemon (rigctld)
#####################################################################
et-log "Updating CAT control configuration..."
sed -i "s|^<CHKUSEHAMLIBIS>.*|<CHKUSEHAMLIBIS>1</CHKUSEHAMLIBIS>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<HAMRIGMODEL>.*|<HAMRIGMODEL>2</HAMRIGMODEL>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<HAMLIBCMDPTT>.*|<HAMLIBCMDPTT>1</HAMLIBCMDPTT>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<HAMRIGDEVICE>.*|<HAMRIGDEVICE>localhost:4532</HAMRIGDEVICE>|" ${FLDIGI_CONF_FILE}
######################################
# Enable Reed Soloman ID for RX and TX
######################################
et-log "Enabling Reed Soloman ID for RX/TX..."
sed -i "s|^<RECEIVERSID>.*|<RECEIVERSID>1</RECEIVERSID>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<TRANSMITRSID>.*|<TRANSMITRSID>1</TRANSMITRSID>|" ${FLDIGI_CONF_FILE}
###########################
# Modem configuration: MT63
###########################
et-log "Updating MT63 modem configuration..."
sed -i "s|^<MT63INTEGRATION>.*|<MT63INTEGRATION>1</MT63INTEGRATION>|" ${FLDIGI_CONF_FILE}
########################
# Repeater configuration
########################
et-log "Updating settings for linked repeater systems..."
# Key up for 2 seconds before transmitting tone. Needed for linked repeater systems.
sed -i "s|^<PRETONE>.*|<PRETONE>2</PRETONE>|" ${FLDIGI_CONF_FILE}
#####################
# NBEMS configuration
#####################
et-log "Updating settings for NBEMS..."
sed -i "s|^<OPEN_NBEMS_FOLDER>.*|<OPEN_NBEMS_FOLDER>1</OPEN_NBEMS_FOLDER>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<FLMSG_PATHNAME>.*|<FLMSG_PATHNAME>/usr/local/bin/flmsg</FLMSG_PATHNAME>|" ${FLDIGI_CONF_FILE}
# TODO: Add flmsg to ETC installer
# TODO: Add flamp to ETC installer
# TODO: Revisit autostart configuration to start flamp
# TODO: Revisit TCP/IP configuration when porting ETC R2 Build 56
# TODO: Define TTP/ETC macros
+89
View File
@@ -0,0 +1,89 @@
/*
* Author : Gaston Gonzalez
* Date : 1 October 2025
* Purpose : Maps an ET_AUDIO ALSA device to a PortAudio device.
*
* This utility enumerates all ALSA audio devices using PortAudio
* to identify a currently plugged-in ET_AUDIO device. If a matching
* device is found, it generates a JSON object on STDOUT containing:
*
* - PortAudio device name
* - PortAudio device index
*
* Exit Status:
* 0 - ET_AUDIO device found and JSON output generated successfully
* 1 - ET_AUDIO device not found
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "portaudio.h"
#define PROC_ALSA_PATH_FMT "/proc/asound/card%d/id"
// Read the ALSA card ID from the /proc filesystem
int get_alsa_card_id(int card, char *id_buf, size_t buf_size) {
char path[64];
snprintf(path, sizeof(path), PROC_ALSA_PATH_FMT, card);
FILE *f = fopen(path, "r");
if (!f) return -1;
if (!fgets(id_buf, buf_size, f)) {
fclose(f);
return -1;
}
id_buf[strcspn(id_buf, "\n")] = 0;
fclose(f);
return 0;
}
int main(void) {
PaError err;
int i, numDevices;
const PaDeviceInfo *deviceInfo;
const PaHostApiInfo *hostApiInfo;
int found = 0;
err = Pa_Initialize();
if (err != paNoError) {
fprintf(stderr, "PortAudio error: %s\n", Pa_GetErrorText(err));
return 1;
}
numDevices = Pa_GetDeviceCount();
if (numDevices < 0) {
fprintf(stderr, "No audio devices found");
Pa_Terminate();
return 1;
}
for (i = 0; i < numDevices; i++) {
deviceInfo = Pa_GetDeviceInfo(i);
hostApiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
// Only show ALSA devices
if (hostApiInfo && strcmp(hostApiInfo->name, "ALSA") == 0) {
int card = -1, device = -1;
// Extract ALSA card and device (hw:X,Y)
if (sscanf(deviceInfo->name, "%*[^()](hw:%d,%d)", &card, &device) == 2) {
char card_id[64];
if (get_alsa_card_id(card, card_id, sizeof(card_id)) == 0) {
// Only print if card ID matches ET_AUDIO
if (strcmp(card_id, "ET_AUDIO") == 0) {
found = 1;
printf("{\n");
printf(" \"device\": \"%s\",\n", deviceInfo->name);
printf(" \"index\": %d\n", i);
printf("}\n");
}
}
}
}
}
Pa_Terminate();
return found ? 0 : 1;
}
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
# Author : Gaston Gonzalez
# Date : 2 October 2025
# Purpose : Test et-portaudio installation
OUT=$(which et-portaudio)
exit $?