Zusätzliche Funktionen in SVXLINK hinzufügen

In SVXLINK können relativ einfach eigene Routinen hinterlegt werden, die z.B. bei einem bestimmten DTMF Kommando oder zu einer bestimmten Uhrzeit ausgelöst werden. Dieser Artikel beschreibt zunächst, wie Aktionen entweder DTMF-gesteuert oder Zeitgesteuert zu einem bestimmten Zeitpunkt ausgelöst werden können.

Alle Funktionen in der Software werden über Events gesteuert, welche in der Programmiersprache TCL definiert sind. Hierbei handelt es sich um einfache Textdateien die direkt im Editor bearbeitet werden können.

Es wird z.B. gesteuert, zu welchem Zeitpunkt etwas passiert. Beispielsweise wird beim Öffnen eines Relais eine bestimmte Audidatei abgespielt. Oder zwischen den Durchgängen wird ein Rogerpiep gesendet. Oder aber es wird in gewissen Zeitabständen eine Bake ausgesendet in Fonie oder CW. Diese Standardfunktionen können durch eigene Funktionen erweitert werden.

Vorbereitungen

Um eigene Funktionen hinzuzufügen, muss man ein paar Vorkehrungen treffen. Alle Routinen befinden sich standardmäßig im Unterordner /usr/share/svxlink/events.d/, dort wechseln wir hin:

cd /usr/share/svxlink/events.d/

Der einfachste Weg ist es meist, die bestehende Datei Logic.tcl dafür zu verwenden. Diese befindet sich entweder im direkt im Ordner events.d oder in einem seperaten Unterordner /usr/share/svxlink/events.d/local/

Im RF-Guru Hotspot-Image ist bzw. der Ordner gar nicht vorhanden, dafür ein symbolischer Link, der wiederrum auf den Ordner /usr/share/svxlink/events.d/ zeigt. Sas sieht man daran, dass sich bei der auflistung des Ordners mit ls -l hinter dem Dateinamen noch eine zusätzliche Angabe steht, z.B.

local -> /usr/share/svxlink/events.d/

Um dies zu ändern, löscht man den symlink mit:

sudo rm /usr/share/svxlink/events.d/local

nun erstellen wir einen neuen gleichlautenden Unterordner, kopieren die Logic.tcl hinein und wechseln in den neuen Unterordner. Wir arbeiten später nur mit dieser Kopie und nicht mit dem Original.

mkdir /usr/share/svxlink/events.d/local
cp Logic.tcl local/
cd local

nun kann man die Logic.tcl editieren.

sudo nano Logic.tcl

Am Ende der Datei findet man den folgenden Abschnitt. Zwischen der vorletzten und der letzten geschweiften Klammer müssen nun alle neuen Funktionen hinterlegt werden.

An dieser Stelle muss erwähnt werden, dass man beim Arbeiten in diesen Dateien Vorsicht walten lassen muss. Diese Logiken werden beim Start von SVXLINK eingelesen. Jeder Syntax-Fehler führt dazu, dass SVXLINK nicht mehr startet. Und in der Regel gibt es auch keine aussagefähige Fehlermledung. Den Fehler dann zu finden, ist schwierig. Also macht bitte vor jeder Änderung eine Sicherungskopie der Datei, um zurück zu kommen.

sudo cp Logic.tcl backup.Logic.tcl

Außerdem muss nach jeder Änderung SVXLINK neu gestartet werden, um die Änderung wirksam zu machen.

sudo systemctl restart svxlink

Aktion per DTMF-Kommando ausführen

# Rufzeichen ausgeben
if {$cmd == "*73001"} {
puts "Spell Callsign";
spellWord $mycall;
return 1
}

Dieses Beispiel würde nach Eingabe des DTMF Kommandos *73001# das Rufzeichen der SVXLINK Installation Buchstabieren.

  • puts = Ausgabe eines Texts im SVXLINK Log
  • spellWord = Text buchstabieren. Hierkann ein Text vorgegeben werden („Text“) oder eine Variable wie z.B. $mycall genutzt werden.

Es gibt noch etliche weitere Kommandos die abgesetzt werden können. Dazu später mehr.

Aktion zeitgesteuert ausführen

Möchte man eine bestimmte Funktion zu einer bestimmten Uhrzeit starten, z.B. eine besondere Ansage, kann man die Funktion „MinuteTickSubscriber“ nutzen. hier ein Beispiel für eine tägliche Aussendung zu einer bestimmten Uhrzeit.

addMinuteTickSubscriber ansage;
#
proc ansage {} {
set now [clock seconds];
set hour [clock format $now -format "%H"];
set minute [clock format $now -format "%M"];

set ansage_Stunde 12;
set ansage_Minute 00;

if {$hour == $ansage_Stunde && $minute == $ansage_Minute} {
puts "Ausgabe Relaisansage";
playMsg "Announcement" "ansage";
}
}

Zunächst werden Variablen mit den aktuellen Zeitinformationen beschrieben (set now, hour, minute). Anschließend wird die gewünschte Auslöse-Zeit definiert in weiteren Variablen. Abschließend wird ein Vergleich durchgeführt. Wenn die Auslösezeit mit der aktuellen Uhrzeit übereinstimmt, wird ein Kommando ausgelöst. Wenn nicht, tut sich nichts. In diesem Beispiel wird täglich um 12 Uhr eine Ansage gespielt (Funktion „playMsg“). Diese muss sich im sounds Ordner im Unterordner „Announcement“ befinden und „ansage.wav“ heißen.

Die Funktion „MinuteTickSubscriber“ wird jede Minute erneut durchlaufen. Es können damit beliebig viele Aktionen definiert werden. Nur wenn die vordefinierte Zeit übereinstimmt, wird eine Aktion ausgelöst.

Beispiel für eine Ansage, die einmal wöchentlich gesendet wird:

addMinuteTickSubscriber wochenansage;
#
proc wochenansage {} {
set now [clock seconds];
set hour [clock format $now -format "%H"];
set minute [clock format $now -format "%M"];
set day [clock format $now -format "%e"];
set weekday [clock format $now -format "%u"];

set ansage_Stunde 20;
set ansage_Minute 15;
set ansage_Wochentag 5;

if {$hour == $ansage_Stunde && $minute == $ansage_Minute && $weekday == $ansage_Wochentag} {
puts "Ausgabe Relaisansage";
playMsg "Announcement" "ansage";
}
}

Hier wird zusätzlich mit der Variable weekday/Wochentag gerabeitet. In diesem beispiel ist Montag = 1 und Sonntag = 7. Die Ansage würde also jeden Freitag um 20:15 Uhr abgespielt werden.

Mögliche Funktionen

Für die folgenden Funktionen gibt es (bzw. wir des geben) Beschreibungen:

  • Ausgabe von Text ins SVXLINK-Log (puts)
  • Audiodatei abspielen (playMsg)
  • Externes Bash Skript ausführen (exec)
  • CW Ausgabe von Text (CW::play)
  • Wartepause zwischen Ansagen (playSilence)
  • Nummer vorlesen (playNumber)
  • Text buchstabieren (spellWord)
  • Zeit vorlesen (playTime)
  • DMTF Ton ausgeben (playDtmf)

Weitere nützliche Funktionen:

  • Vordefinierten DTMF-Code gezielt auslösen, z.B. zu einer bestimmten Uhrzeit.
  • Rundspruch zeitgesteuert aussenden
  • Ansage zu einer bestimmten Uhrzeit aussenden

Ausgabe von Text ins SVXLINK-Log (puts)

Man kann in einer Funktion einen beliebigen Text in das SVXLINK-Log schreiben lassen. Dadurch kann man z.B. nachvollziehen, ob eine bestimmte Funktion auch ausgelöst wurde.

puts "Ausgabe Relaisansage";

Erzeugt im Log:

Tue Mar 18 12:00:00 2025: Ausgabe Relaisansage

Audiodatei abspielen (playMsg)

Es können in einer Funktion lokal vorliegende Sounddateien abgespielt werden. Diese müssen in den „sounds“ Ordnern der jeweiligen Sprache abgespeichert sein. Wenn man die deutschen Sprachdateien hat, wäre dies der Ordner:

/usr/share/svxlink/sounds/de_DE

Wichtig ist hier auch die Angabe der korrekten Sprache in der svxlink.conf. Für die dort angegebene Sprache muss auch ein Unterordner mit Sounddateien unter /usr/share/svxlink/sounds/ existieren, sonst können die Audiodateien nicht abgespielt werden. In jeder Logic kann theoretisch eine eigene Sprache verwendet werden.

[ReflectorLogic]
DEFAULT_LANG=de_DE

[SimplexLogic]
DEFAULT_LANG=de_DE

[ReflectorLogic]
DEFAULT_LANG=de_DE

Im Sounds-ordner der jeweiligen Sprache gibt es mehrere Unterordner, dies sind dann die „Kategorien“, die man beim Kommando neben dem Namen der Audiodatei ansprechen muss. Dies ist ein Beispiel der möglichen Unterordner. Je nach Quelle des Sprachpakets kann dies variieren.

user@host:/usr/share/svxlink/sounds/de_DE$ ls -l
drwxr-xr-x 3 svxlink svxlink 4096 Mar 17 16:24 Announcement
drwxr-xr-x 3 svxlink svxlink 4096 Jan 3 20:25 Core
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:10 Default
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:10 DtmfRepeater
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:10 EchoLink
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:10 events.d
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:10 Help
drwxr-xr-x 3 svxlink svxlink 4096 Jan 3 18:10 KatWarn
drwxr-xr-x 2 svxlink svxlink 12288 Jan 3 18:11 MetarInfo
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:11 Parrot
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:11 PhoneLogic
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:11 PropagationMonitor
-rwxr-xr-x 1 svxlink svxlink 294 Oct 9 22:08 README.md
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:11 Rundspruch
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:11 SelCallEnc
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:11 SipLogic
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:11 TclVoiceMail
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:11 Temp
drwxr-xr-x 2 svxlink svxlink 4096 Jan 3 18:11 TrafficInfo
drwxr-xr-x 3 svxlink svxlink 4096 Jan 3 18:11 WeatherInfo

Hier gibt es wichtige Kategorien wie „Core“, „Help“, „Echolink“ usw.

Möchte man nun eine bestimmte Audiodatei abspielen, muss man in der TCL-Funktion folgendes Kommando angeben:

playMsg "Announcement" "ansage";

Dies bedeutet, dass im jeweiligen Sprachordner im Unterordner „Announcement“ die Audodatei „ansage.wav“ abgespielt werden soll. Noch ein Beispiel:

playMsg "Core" "Tollpatsch";

Dies würde im Unterordner „Core“ die Datei „Tollpatsch.wav“ abspielen. Wird die Datei nicht gefunden, wird nichts abgespielt und es erscheint eine Fehlermeldung im SVXLINK-Log.

Und in welchem Format müssen die Audiodateien vorliegen?

  • WAV-Format
  • Mono
  • Samplerate 16000 Hz
  • 16 Bit

Weitere Audioformate konnte ich noch nicht abspielen, aber vielleicht geht dies auch irgendwie.

Externes Bash Skript ausführen (exec)

Man kann in einer Funktion auch eine lokal liegende Skriptdatei ausführen lassen, in der weitere Linuxbefehle ausgeführt werden. Diese Dateien werden mit den Rechten des Users „svxlink“ ausgeführt, unter dem SVXLINK ausgeführt wird. Es ist also für entsprechende Zugriffsrechte auf die Datei zu sorgen. Wenn man z.B. den Rechner per Kommando neu starten möchte, dann sieht das so aus:

exec bash /etc/svxlink/scripts/reboot.sh;

Die Skriptdatei /etc/svxlink/scripts/reboot.sh enthält dann bspw. folgendes:

#!bin/bash
sudo reboot

CW Ausgabe von Text (CW::play)

Es ist möglich an beliebiger Stelle einen Text in CW auszugeben. Man kann den Text in literalen „TEXT“ angeben, aber auch eine Variable, $mycall z.B., was das eigene Rufzeichen ausgeben würde.

CW::play "morse mich";
CW::play $mycall;

Wo Tonhöhe und Geschwindigkeit einzurichten sind, finde ich noch raus und ergänze es bei Bedarf.

Wartepause zwischen Ansagen (playSilence)

Wenn man in einer Funktion mehrere Schritte abarbeitet, möchte man ggf. auch eine kurze Pause einfügen, z.B. zwischen zwei Ansagen. Mit diesem Kommando ist dies möglich. Die Werte werden in Millisekunden angegeben, eine Sekunde entspricht dem Wert „1000“.

playSilence 500;

Nummer vorlesen (playNumber)

Mit playNumber kann man Zahlen vorlesen lassen. Achtung: Nicht immer wird dies aber korrekt ausgesprochen, je nach Konfiguration.

playNumber "123";
playNumber $s1;

Text buchstabieren (spellWord)

Man kann auch Text buchstabieren lassen. Es wird das Nato-Alphabet verwendet (Alpha, Bravo, Charlie …). Die Autiodateien dafür liegen unter /sound/<Sprache>/Default/

spellWord "DB0XYZ";
spellWord $mycall;

Zeit vorlesen (playTime)

Man kann auch eine Uhrzeit vorlesen lassen. Dazu müssen Variablen mit der vorzusagenden Uhrzeit gefüllt werden. Hier ein Beispiel wie die aktuelle Uhrzeit angesagt werden kann:

set epoch [clock seconds];
set hour [clock format $epoch -format "%k"];
regexp {([1-5]?\d)$} [clock format $epoch -format "%M"] -> minute;
playTime $hour $minute;

DMTF Ton ausgeben (playDtmf)

Ob Sinn oder Unsinn, man kann eine DTMF-Folge aussenden lassen. Für welche Zwecke auch immer. Es wird also vom Relais/Hotspot eine DTMF-Folge ausgestrahlt. Das Relais bzw. der Hotspot wird aber selbst nicht auf dieses DTMF Kommando reagieren.

playDtmf "12345" "500" "50"

In diesem Beispiel würde der DTMF-Code 12345 ausgesendet werden. Dabei gibt der zweite Zahlenwert die Dauer der Aussendung eines Zeichens in Millisekunden an. 50 entspricht als 50ms. Je höher der Wert gewählt wird, umso „langsamer“ wird die Zeichenfolge ausgegeben und umso länger dauert die Aussendung. Was der erste Wert bedeutet, ist mir unbekannt. Ich habe es mit 200, 1000 und 5000 versucht, es hat meiner Meinung nach keine Auswirkung auf die Aussendung gehabt. Vielleicht weiß jemand mehr.