Fix hanging exec cmd instances, rework exec cmdline args

This commit is contained in:
Nonoo 2020-11-03 10:42:38 +01:00
parent 47a22e5cce
commit c98f1bd7a8
6 changed files with 93 additions and 59 deletions

View file

@ -53,33 +53,19 @@ host **ic-705** (ic-705.local or ic-705.localdomain).
After it is connected and logged in:
- Creates a virtual PulseAudio **sound card** (48kHz, s16le, mono). This can be
used to record/play audio from/to the server (the radio). You can also set
this sound card in [WSJT-X](https://physics.princeton.edu/pulsar/K1JT/wsjtx.html).
If you want to listen to the audio coming from this sound card in real time,
then you can create a [PulseAudio loopback](https://github.com/alentoghostflame/Python-Pulseaudio-Loopback-Tool)
between the kappanhang sound card and your real sound card. You can also
create a loopback for your microphone using this tool, so you'll be able to
transmit your voice.
used to record/play audio from/to the server (the transceiver). You can also
set this sound card in [WSJT-X](https://physics.princeton.edu/pulsar/K1JT/wsjtx.html).
- Starts a **TCP server** on port `4533` for exposing the **serial port**.
- Starts `rigctld` and connects it to kappanhang's TCP serial port server.
This can be used for controlling the server (the transceiver) with
[Hamlib](https://hamlib.github.io/) (`rigctld`).
- Runs the command `rigctld -m 3085 -r :4533` which starts `rigctld` and
connects it to kappanhang's TCP serial port server. You can specify a custom
command with the `-r` command line argument. Running any command can be
disabled with `-r -`. The command is only executed once, as the TCP serial
port server will stay on even if the RS-BA1 server disconnects. If the TCP
serial port client disconnects (rigctld hangs) then the command will be
automatically restarted. This can be disabled with the `-e`.
3085 is the model number of the Icom IC-705. `rigctld` will connect to
kappanhang's TCP serial port server, and waits connections on it's default
TCP port `4532`.
To use this with for example [WSJT-X](https://physics.princeton.edu/pulsar/K1JT/wsjtx.html),
open WSJT-X settings, go to the *Radio* tab, set the *rig type* to `Hamlib NET
rigctl`, and the *Network server* to `localhost`.
### Notes on command line arguments
If the `-s` command line argument is specified, then kappanhang will create a
**virtual serial port**, so other apps which don't support Hamlib can access
the transceiver directly. Look at the app log to find out the name of the
@ -148,18 +134,12 @@ not available.
### Hotkeys
- `q` (quit): closes the app
- `l` (listen): toggles audio stream playback to the default sound device
- `l` (listen): toggles audio stream playback to the default sound device.
This is useful for quickly listening into the audio stream coming from the
server (the transceiver).
Note that audio will be played to the previously created virtual sound card
regardless of this setting.
- `space`: toggles PTT and audio stream recording from the default sound
device
You can transmit your own voice using a mic attached to your computer for
example.
device. You can transmit your own voice using a mic attached to your
computer for example.
Some basic CAT control hotkeys are also supported:

17
args.go
View file

@ -12,8 +12,9 @@ var verboseLog bool
var connectAddress string
var serialTCPPort uint16
var enableSerialDevice bool
var rigctldModel uint
var disableRigctld bool
var runCmd string
var disableReRunCmd bool
var runCmdOnSerialPortCreated string
var statusLogInterval time.Duration
@ -21,11 +22,12 @@ func parseArgs() {
h := getopt.BoolLong("help", 'h', "display help")
v := getopt.BoolLong("verbose", 'v', "Enable verbose (debug) logging")
a := getopt.StringLong("address", 'a', "IC-705", "Connect to address")
t := getopt.Uint16Long("serial-tcp-port", 'p', 4533, "Expose radio's serial port on this TCP port")
t := getopt.Uint16Long("serial-tcp-port", 't', 4533, "Expose radio's serial port on this TCP port")
s := getopt.BoolLong("enable-serial-device", 's', "Expose radio's serial port as a virtual serial port")
r := getopt.StringLong("run", 'r', "rigctld -m 3085 -r :4533", "Exec cmd when connected, set to - to disable")
e := getopt.BoolLong("disable-rerun", 'e', "Disable re-execing the cmd on TCP serial port disconnect")
o := getopt.StringLong("run-serial", 'o', "socat /tmp/kappanhang-IC-705.pty /tmp/vmware.pty", "Exec cmd when virtual serial port is created, set to - to disable")
m := getopt.UintLong("rigctld-model", 'm', 3085, "rigctld model number")
r := getopt.BoolLong("disable-rigctld", 'r', "Disable starting rigctld")
e := getopt.StringLong("exec", 'e', "", "Exec cmd when connected")
o := getopt.StringLong("exec-serial", 'o', "socat /tmp/kappanhang-IC-705.pty /tmp/vmware.pty", "Exec cmd when virtual serial port is created, set to - to disable")
i := getopt.Uint16Long("log-interval", 'i', 100, "Status bar/log interval in milliseconds")
getopt.Parse()
@ -40,8 +42,9 @@ func parseArgs() {
connectAddress = *a
serialTCPPort = *t
enableSerialDevice = *s
runCmd = *r
disableReRunCmd = *e
rigctldModel = *m
disableRigctld = *r
runCmd = *e
runCmdOnSerialPortCreated = *o
statusLogInterval = time.Duration(*i) * time.Millisecond
}

View file

@ -259,9 +259,8 @@ func (s *controlStream) handleRead(r []byte) error {
statusLog.startPeriodicPrint()
startCmdIfNeeded()
if enableSerialDevice {
startSerialPortCmdIfNeeded()
}
startSerialPortCmdIfNeeded()
startRigctldCmdIfNeeded()
}
}
return nil

View file

@ -134,6 +134,7 @@ func main() {
stopCmd()
stopSerialPortCmd()
stopRigctldCmd()
audio.deinit()
serialTCPSrv.deinit()
serialPort.deinit()

View file

@ -1,6 +1,7 @@
package main
import (
"fmt"
"os/exec"
"strings"
"time"
@ -8,8 +9,48 @@ import (
const startCmdDelay = time.Second
var startedRigctldCmd *exec.Cmd
var rigctldCmdStartTimer *time.Timer
var startedCmd *exec.Cmd
var cmdStartTimer *time.Timer
var serialPortStartedCmd *exec.Cmd
var serialPortCmdStartTimer *time.Timer
func doStartRigctldCmd() {
startedRigctldCmd = exec.Command("rigctld", "-m", fmt.Sprint(rigctldModel), "-r",
fmt.Sprint(":", serialTCPPort))
err := startedRigctldCmd.Start()
if err == nil {
log.Print("rigctld started: ", startedRigctldCmd)
} else {
log.Error("error starting rigctld: ", err)
startedCmd = nil
}
rigctldCmdStartTimer = nil
}
func startRigctldCmdIfNeeded() {
if startedRigctldCmd != nil || disableRigctld {
return
}
if rigctldCmdStartTimer != nil {
rigctldCmdStartTimer.Stop()
}
rigctldCmdStartTimer = time.AfterFunc(startCmdDelay, doStartRigctldCmd)
}
func stopRigctldCmd() {
if startedRigctldCmd == nil {
return
}
if err := startedRigctldCmd.Process.Kill(); err != nil {
log.Error("failed to stop rigctld: ", err)
}
_ = startedRigctldCmd.Wait()
startedRigctldCmd = nil
}
func doStartCmd() {
c := strings.Split(runCmd, " ")
@ -21,14 +62,29 @@ func doStartCmd() {
log.Error("error starting ", runCmd, ": ", err)
startedCmd = nil
}
cmdStartTimer = nil
}
func startCmdIfNeeded() {
if startedCmd != nil || runCmd == "-" {
if startedCmd != nil || runCmd == "" {
return
}
time.AfterFunc(startCmdDelay, doStartCmd)
if cmdStartTimer != nil {
cmdStartTimer.Stop()
}
cmdStartTimer = time.AfterFunc(startCmdDelay, doStartCmd)
}
func stopCmd() {
if startedCmd == nil {
return
}
if err := startedCmd.Process.Kill(); err != nil {
log.Error("failed to stop cmd ", runCmd, ": ", err)
}
startedCmd = nil
}
func doSerialPortStartCmd() {
@ -41,30 +97,27 @@ func doSerialPortStartCmd() {
log.Error("error starting ", runCmdOnSerialPortCreated, ": ", err)
serialPortStartedCmd = nil
}
serialPortCmdStartTimer = nil
}
func startSerialPortCmdIfNeeded() {
if serialPortStartedCmd != nil || runCmdOnSerialPortCreated == "-" {
if !enableSerialDevice || serialPortStartedCmd != nil || runCmdOnSerialPortCreated == "-" {
return
}
time.AfterFunc(startCmdDelay, doSerialPortStartCmd)
}
func stopCmd() {
if startedCmd != nil {
if err := startedCmd.Process.Kill(); err != nil {
log.Error("failed to stop cmd ", runCmd, ": ", err)
}
startedCmd = nil
if serialPortCmdStartTimer != nil {
serialPortCmdStartTimer.Stop()
}
serialPortCmdStartTimer = time.AfterFunc(startCmdDelay, doSerialPortStartCmd)
}
func stopSerialPortCmd() {
if serialPortStartedCmd != nil {
if err := serialPortStartedCmd.Process.Kill(); err != nil {
log.Error("failed to stop cmd ", runCmdOnSerialPortCreated, ": ", err)
}
serialPortStartedCmd = nil
if serialPortStartedCmd == nil {
return
}
if err := serialPortStartedCmd.Process.Kill(); err != nil {
log.Error("failed to stop cmd ", runCmdOnSerialPortCreated, ": ", err)
}
serialPortStartedCmd = nil
}

View file

@ -104,10 +104,8 @@ func (s *serialTCPSrvStruct) loop() {
s.disconnectClient()
log.Print("client ", s.client.RemoteAddr().String(), " disconnected")
if !disableReRunCmd {
stopCmd()
startCmdIfNeeded()
}
stopRigctldCmd()
startRigctldCmdIfNeeded()
}
}