diff --git a/README.md b/README.md index a604707..60ff56b 100644 --- a/README.md +++ b/README.md @@ -59,11 +59,11 @@ After it is connected and logged in: transmit your voice. - Starts a **TCP server** on port `4533` for exposing the **serial port**. This can be used for controlling the server (the transceiver) with - [Hamlib](https://hamlib.github.io/): - - ``` - rigctld -m 3085 -r 127.0.0.1:4533 - ``` + [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 -`. 3085 is the model number for the Icom IC-705. `rigctld` will connect to kappanhang's TCP serial port server, and waits connections on it's default @@ -84,7 +84,8 @@ Note that the built-in Wi-Fi in the Icom IC-705 has **very limited range**, and **sensitive to interference**. If you see a lot of retransmits in the log, or packet loss, then: -- Place the IC-705 close to your Wi-Fi AP/router +- Place the IC-705 close to your Wi-Fi AP/router, or use a Wi-Fi range + extender device. - Make sure the Wi-Fi bandwith is set to max. 20Mhz in the Wi-Fi router (see explanation [here](https://superuser.com/questions/542191/does-moving-my-router-from-20mhz-to-40-mhz-increase-my-wireless-speed)) - Try switching Wi-Fi channel on your Wi-Fi router. Only channels 1, 6 or 11 diff --git a/args.go b/args.go index a8d6e8d..03c678c 100644 --- a/args.go +++ b/args.go @@ -12,6 +12,7 @@ var verboseLog bool var connectAddress string var serialTCPPort uint16 var enableSerialDevice bool +var runCmd string var statusLogInterval time.Duration func parseArgs() { @@ -20,6 +21,7 @@ func parseArgs() { 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") 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") i := getopt.Uint16Long("log-interval", 'i', 100, "Status bar/log interval in milliseconds") getopt.Parse() @@ -34,5 +36,6 @@ func parseArgs() { connectAddress = *a serialTCPPort = *t enableSerialDevice = *s + runCmd = *r statusLogInterval = time.Duration(*i) * time.Millisecond } diff --git a/controlstream.go b/controlstream.go index ef328ef..5694180 100644 --- a/controlstream.go +++ b/controlstream.go @@ -259,6 +259,8 @@ func (s *controlStream) handleRead(r []byte) error { s.serialAndAudioStreamOpened = true statusLog.startPeriodicPrint() + + startCmdIfNeeded() } } return nil diff --git a/log.go b/log.go index 02d8ea9..621bf89 100644 --- a/log.go +++ b/log.go @@ -27,18 +27,14 @@ func (l *logger) GetCallerFileName(withLine bool) string { } } -func (l *logger) Printf(a string, b ...interface{}) { - if statusLog.isRealtime() { - statusLog.clear() - defer statusLog.print() - } - l.logger.Infof(l.GetCallerFileName(false)+": "+a, b...) -} - func (l *logger) Print(a ...interface{}) { if statusLog.isRealtime() { - statusLog.clear() - defer statusLog.print() + statusLog.mutex.Lock() + statusLog.clearInternal() + defer func() { + statusLog.mutex.Unlock() + statusLog.print() + }() } l.logger.Info(append([]interface{}{l.GetCallerFileName(false) + ": "}, a...)...) } @@ -47,62 +43,42 @@ func (l *logger) PrintStatusLog(a ...interface{}) { l.logger.Info(append([]interface{}{l.GetCallerFileName(false) + ": "}, a...)...) } -func (l *logger) Debugf(a string, b ...interface{}) { - if statusLog.isRealtime() { - statusLog.clear() - defer statusLog.print() - } - l.logger.Debugf(l.GetCallerFileName(true)+": "+a, b...) -} - func (l *logger) Debug(a ...interface{}) { if statusLog.isRealtime() { - statusLog.clear() - defer statusLog.print() + statusLog.mutex.Lock() + statusLog.clearInternal() + defer func() { + statusLog.mutex.Unlock() + statusLog.print() + }() } l.logger.Debug(append([]interface{}{l.GetCallerFileName(true) + ": "}, a...)...) } -func (l *logger) Errorf(a string, b ...interface{}) { - if statusLog.isRealtime() { - statusLog.clear() - defer statusLog.print() - } - l.logger.Errorf(l.GetCallerFileName(true)+": "+a, b...) -} - func (l *logger) Error(a ...interface{}) { if statusLog.isRealtime() { - statusLog.clear() - defer statusLog.print() + statusLog.mutex.Lock() + statusLog.clearInternal() + defer func() { + statusLog.mutex.Unlock() + statusLog.print() + }() } l.logger.Error(append([]interface{}{l.GetCallerFileName(true) + ": "}, a...)...) } func (l *logger) ErrorC(a ...interface{}) { if statusLog.isRealtime() { - statusLog.clear() - defer statusLog.print() + statusLog.mutex.Lock() + statusLog.clearInternal() + defer func() { + statusLog.mutex.Unlock() + statusLog.print() + }() } l.logger.Error(a...) } -func (l *logger) Fatalf(a string, b ...interface{}) { - if statusLog.isRealtime() { - statusLog.clear() - defer statusLog.print() - } - l.logger.Fatalf(l.GetCallerFileName(true)+": "+a, b...) -} - -func (l *logger) Fatal(a ...interface{}) { - if statusLog.isRealtime() { - statusLog.clear() - defer statusLog.print() - } - l.logger.Fatal(append([]interface{}{l.GetCallerFileName(true) + ": "}, a...)...) -} - func (l *logger) Init() { // Example: https://stackoverflow.com/questions/50933936/zap-logger-does-not-print-on-console-rather-print-in-the-log-file/50936341 pe := zap.NewProductionEncoderConfig() diff --git a/main.go b/main.go index 1925c99..037f29c 100644 --- a/main.go +++ b/main.go @@ -110,6 +110,7 @@ func main() { } } + stopCmd() audio.deinit() serialTCPSrv.deinit() serialPort.deinit() diff --git a/runcmd.go b/runcmd.go new file mode 100644 index 0000000..5a94a89 --- /dev/null +++ b/runcmd.go @@ -0,0 +1,40 @@ +package main + +import ( + "os/exec" + "strings" + "time" +) + +const startCmdDelay = time.Second + +var startedCmd *exec.Cmd + +func doStartCmd() { + c := strings.Split(runCmd, " ") + startedCmd = exec.Command(c[0], c[1:]...) + err := startedCmd.Start() + if err == nil { + log.Print("cmd started: ", runCmd) + } else { + log.Error("error starting ", runCmd, " - ", err) + startedCmd = nil + } +} + +func startCmdIfNeeded() { + if startedCmd != nil || runCmd == "-" { + return + } + + time.AfterFunc(startCmdDelay, doStartCmd) +} + +func stopCmd() { + if startedCmd == nil { + return + } + if err := startedCmd.Process.Kill(); err != nil { + log.Error("failed to stop cmd ", runCmd) + } +} diff --git a/statuslog.go b/statuslog.go index 73057b1..bd6c233 100644 --- a/statuslog.go +++ b/statuslog.go @@ -97,13 +97,6 @@ func (s *statusLogStruct) clearInternal() { fmt.Printf("%c[2K", 27) } -func (s *statusLogStruct) clear() { - s.mutex.Lock() - defer s.mutex.Unlock() - - s.clearInternal() -} - func (s *statusLogStruct) print() { s.mutex.Lock() defer s.mutex.Unlock()