mirror of
https://github.com/nonoo/kappanhang.git
synced 2025-12-06 08:02:00 +01:00
Fix hanging exec cmd instances, rework exec cmdline args
This commit is contained in:
parent
47a22e5cce
commit
c98f1bd7a8
36
README.md
36
README.md
|
|
@ -53,33 +53,19 @@ host **ic-705** (ic-705.local or ic-705.localdomain).
|
||||||
After it is connected and logged in:
|
After it is connected and logged in:
|
||||||
|
|
||||||
- Creates a virtual PulseAudio **sound card** (48kHz, s16le, mono). This can be
|
- 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
|
used to record/play audio from/to the server (the transceiver). You can also
|
||||||
this sound card in [WSJT-X](https://physics.princeton.edu/pulsar/K1JT/wsjtx.html).
|
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.
|
|
||||||
- Starts a **TCP server** on port `4533` for exposing the **serial port**.
|
- 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
|
This can be used for controlling the server (the transceiver) with
|
||||||
[Hamlib](https://hamlib.github.io/) (`rigctld`).
|
[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),
|
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
|
open WSJT-X settings, go to the *Radio* tab, set the *rig type* to `Hamlib NET
|
||||||
rigctl`, and the *Network server* to `localhost`.
|
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
|
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
|
**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
|
the transceiver directly. Look at the app log to find out the name of the
|
||||||
|
|
@ -148,18 +134,12 @@ not available.
|
||||||
### Hotkeys
|
### Hotkeys
|
||||||
|
|
||||||
- `q` (quit): closes the app
|
- `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
|
This is useful for quickly listening into the audio stream coming from the
|
||||||
server (the transceiver).
|
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
|
- `space`: toggles PTT and audio stream recording from the default sound
|
||||||
device
|
device. You can transmit your own voice using a mic attached to your
|
||||||
|
computer for example.
|
||||||
You can transmit your own voice using a mic attached to your computer for
|
|
||||||
example.
|
|
||||||
|
|
||||||
Some basic CAT control hotkeys are also supported:
|
Some basic CAT control hotkeys are also supported:
|
||||||
|
|
||||||
|
|
|
||||||
17
args.go
17
args.go
|
|
@ -12,8 +12,9 @@ var verboseLog bool
|
||||||
var connectAddress string
|
var connectAddress string
|
||||||
var serialTCPPort uint16
|
var serialTCPPort uint16
|
||||||
var enableSerialDevice bool
|
var enableSerialDevice bool
|
||||||
|
var rigctldModel uint
|
||||||
|
var disableRigctld bool
|
||||||
var runCmd string
|
var runCmd string
|
||||||
var disableReRunCmd bool
|
|
||||||
var runCmdOnSerialPortCreated string
|
var runCmdOnSerialPortCreated string
|
||||||
var statusLogInterval time.Duration
|
var statusLogInterval time.Duration
|
||||||
|
|
||||||
|
|
@ -21,11 +22,12 @@ func parseArgs() {
|
||||||
h := getopt.BoolLong("help", 'h', "display help")
|
h := getopt.BoolLong("help", 'h', "display help")
|
||||||
v := getopt.BoolLong("verbose", 'v', "Enable verbose (debug) logging")
|
v := getopt.BoolLong("verbose", 'v', "Enable verbose (debug) logging")
|
||||||
a := getopt.StringLong("address", 'a', "IC-705", "Connect to address")
|
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")
|
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")
|
m := getopt.UintLong("rigctld-model", 'm', 3085, "rigctld model number")
|
||||||
e := getopt.BoolLong("disable-rerun", 'e', "Disable re-execing the cmd on TCP serial port disconnect")
|
r := getopt.BoolLong("disable-rigctld", 'r', "Disable starting rigctld")
|
||||||
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")
|
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")
|
i := getopt.Uint16Long("log-interval", 'i', 100, "Status bar/log interval in milliseconds")
|
||||||
|
|
||||||
getopt.Parse()
|
getopt.Parse()
|
||||||
|
|
@ -40,8 +42,9 @@ func parseArgs() {
|
||||||
connectAddress = *a
|
connectAddress = *a
|
||||||
serialTCPPort = *t
|
serialTCPPort = *t
|
||||||
enableSerialDevice = *s
|
enableSerialDevice = *s
|
||||||
runCmd = *r
|
rigctldModel = *m
|
||||||
disableReRunCmd = *e
|
disableRigctld = *r
|
||||||
|
runCmd = *e
|
||||||
runCmdOnSerialPortCreated = *o
|
runCmdOnSerialPortCreated = *o
|
||||||
statusLogInterval = time.Duration(*i) * time.Millisecond
|
statusLogInterval = time.Duration(*i) * time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -259,9 +259,8 @@ func (s *controlStream) handleRead(r []byte) error {
|
||||||
statusLog.startPeriodicPrint()
|
statusLog.startPeriodicPrint()
|
||||||
|
|
||||||
startCmdIfNeeded()
|
startCmdIfNeeded()
|
||||||
if enableSerialDevice {
|
startSerialPortCmdIfNeeded()
|
||||||
startSerialPortCmdIfNeeded()
|
startRigctldCmdIfNeeded()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
1
main.go
1
main.go
|
|
@ -134,6 +134,7 @@ func main() {
|
||||||
|
|
||||||
stopCmd()
|
stopCmd()
|
||||||
stopSerialPortCmd()
|
stopSerialPortCmd()
|
||||||
|
stopRigctldCmd()
|
||||||
audio.deinit()
|
audio.deinit()
|
||||||
serialTCPSrv.deinit()
|
serialTCPSrv.deinit()
|
||||||
serialPort.deinit()
|
serialPort.deinit()
|
||||||
|
|
|
||||||
87
runcmd.go
87
runcmd.go
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -8,8 +9,48 @@ import (
|
||||||
|
|
||||||
const startCmdDelay = time.Second
|
const startCmdDelay = time.Second
|
||||||
|
|
||||||
|
var startedRigctldCmd *exec.Cmd
|
||||||
|
var rigctldCmdStartTimer *time.Timer
|
||||||
var startedCmd *exec.Cmd
|
var startedCmd *exec.Cmd
|
||||||
|
var cmdStartTimer *time.Timer
|
||||||
var serialPortStartedCmd *exec.Cmd
|
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() {
|
func doStartCmd() {
|
||||||
c := strings.Split(runCmd, " ")
|
c := strings.Split(runCmd, " ")
|
||||||
|
|
@ -21,14 +62,29 @@ func doStartCmd() {
|
||||||
log.Error("error starting ", runCmd, ": ", err)
|
log.Error("error starting ", runCmd, ": ", err)
|
||||||
startedCmd = nil
|
startedCmd = nil
|
||||||
}
|
}
|
||||||
|
cmdStartTimer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startCmdIfNeeded() {
|
func startCmdIfNeeded() {
|
||||||
if startedCmd != nil || runCmd == "-" {
|
if startedCmd != nil || runCmd == "" {
|
||||||
return
|
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() {
|
func doSerialPortStartCmd() {
|
||||||
|
|
@ -41,30 +97,27 @@ func doSerialPortStartCmd() {
|
||||||
log.Error("error starting ", runCmdOnSerialPortCreated, ": ", err)
|
log.Error("error starting ", runCmdOnSerialPortCreated, ": ", err)
|
||||||
serialPortStartedCmd = nil
|
serialPortStartedCmd = nil
|
||||||
}
|
}
|
||||||
|
serialPortCmdStartTimer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startSerialPortCmdIfNeeded() {
|
func startSerialPortCmdIfNeeded() {
|
||||||
if serialPortStartedCmd != nil || runCmdOnSerialPortCreated == "-" {
|
if !enableSerialDevice || serialPortStartedCmd != nil || runCmdOnSerialPortCreated == "-" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
time.AfterFunc(startCmdDelay, doSerialPortStartCmd)
|
if serialPortCmdStartTimer != nil {
|
||||||
}
|
serialPortCmdStartTimer.Stop()
|
||||||
|
|
||||||
func stopCmd() {
|
|
||||||
if startedCmd != nil {
|
|
||||||
if err := startedCmd.Process.Kill(); err != nil {
|
|
||||||
log.Error("failed to stop cmd ", runCmd, ": ", err)
|
|
||||||
}
|
|
||||||
startedCmd = nil
|
|
||||||
}
|
}
|
||||||
|
serialPortCmdStartTimer = time.AfterFunc(startCmdDelay, doSerialPortStartCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopSerialPortCmd() {
|
func stopSerialPortCmd() {
|
||||||
if serialPortStartedCmd != nil {
|
if serialPortStartedCmd == nil {
|
||||||
if err := serialPortStartedCmd.Process.Kill(); err != nil {
|
return
|
||||||
log.Error("failed to stop cmd ", runCmdOnSerialPortCreated, ": ", err)
|
|
||||||
}
|
|
||||||
serialPortStartedCmd = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := serialPortStartedCmd.Process.Kill(); err != nil {
|
||||||
|
log.Error("failed to stop cmd ", runCmdOnSerialPortCreated, ": ", err)
|
||||||
|
}
|
||||||
|
serialPortStartedCmd = nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,10 +104,8 @@ func (s *serialTCPSrvStruct) loop() {
|
||||||
s.disconnectClient()
|
s.disconnectClient()
|
||||||
log.Print("client ", s.client.RemoteAddr().String(), " disconnected")
|
log.Print("client ", s.client.RemoteAddr().String(), " disconnected")
|
||||||
|
|
||||||
if !disableReRunCmd {
|
stopRigctldCmd()
|
||||||
stopCmd()
|
startRigctldCmdIfNeeded()
|
||||||
startCmdIfNeeded()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue