mirror of
https://github.com/nonoo/kappanhang.git
synced 2026-01-10 18:59:59 +01:00
Add displaying PTT/freq/mode info to the status bar
This commit is contained in:
parent
9957abbb46
commit
dfb5dbd948
32
README.md
32
README.md
|
|
@ -78,17 +78,25 @@ If the `-s` command line argument is specified, then kappanhang will create a
|
|||
the transceiver directly. Look at the app log to find out the name of the
|
||||
virtual serial port.
|
||||
|
||||
### Status log
|
||||
### Status bar
|
||||
|
||||
kappanhang displays a "realtime" status log (when the audio/serial connection
|
||||
kappanhang displays a "realtime" status bar (when the audio/serial connection
|
||||
is up) with the following info:
|
||||
|
||||
- `up`: how long the audio/serial connection is active
|
||||
- `rtt`: roundtrip communication latency with the server
|
||||
- `up/down`: currently used upload/download bandwidth (only considering UDP
|
||||
payload to/from the server)
|
||||
- `retx`: audio/serial retransmit request count to/from the server
|
||||
- `lost`: lost audio/serial packet count from the server
|
||||
- First status bar line:
|
||||
- `state`: RX/TX/TUNE depending on the PTT status
|
||||
- `freq`: operating frequency in MHz, mode (LSB/USB/FM...), active filter
|
||||
|
||||
- Second status bar line:
|
||||
- `up`: how long the audio/serial connection is active
|
||||
- `rtt`: roundtrip communication latency with the server
|
||||
- `up/down`: currently used upload/download bandwidth (only considering UDP
|
||||
payload to/from the server)
|
||||
- `retx`: audio/serial retransmit request count to/from the server
|
||||
- `lost`: lost audio/serial packet count from the server
|
||||
|
||||
Data for the first status bar line is acquired by monitoring CiV traffic in
|
||||
the serial stream.
|
||||
|
||||
`retx` and `lost` are displayed in a 1 minute window, which means they will be
|
||||
reset to 0 if they don't increase for 1 minute. A `retx` value other than 0
|
||||
|
|
@ -97,9 +105,11 @@ if `loss` stays 0 then the issues were fixed using packet retransmission.
|
|||
`loss` indicates failed retransmit sequences, so packet loss. This can cause
|
||||
audio and serial communication disruptions.
|
||||
|
||||
If the status log interval (can be changed with the `-i` command line
|
||||
argument) is equal to or above 1 second, then the realtime status log will be
|
||||
disabled and all status log lines will be written as new console lines.
|
||||
If status bar interval (can be changed with the `-i` command line
|
||||
argument) is equal to or above 1 second, then the realtime status bar will be
|
||||
disabled and the contents of the second line of the status bar will be written
|
||||
as new console log lines. This is also the case if a Unix/VT100 terminal is
|
||||
not available.
|
||||
|
||||
## Authors
|
||||
|
||||
|
|
|
|||
2
args.go
2
args.go
|
|
@ -20,7 +20,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")
|
||||
i := getopt.Uint16Long("log-interval", 'i', 100, "Status log interval in milliseconds")
|
||||
i := getopt.Uint16Long("log-interval", 'i', 100, "Status bar/log interval in milliseconds")
|
||||
|
||||
getopt.Parse()
|
||||
|
||||
|
|
|
|||
122
civdecoder.go
Normal file
122
civdecoder.go
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
package main
|
||||
|
||||
import "math"
|
||||
|
||||
const civAddress = 0xa4
|
||||
|
||||
type civDecoderStruct struct {
|
||||
}
|
||||
|
||||
func (s *civDecoderStruct) decode(d []byte) {
|
||||
if len(d) < 6 || d[0] != 0xfe || d[1] != 0xfe || d[len(d)-1] != 0xfd {
|
||||
return
|
||||
}
|
||||
|
||||
payload := d[5 : len(d)-1]
|
||||
|
||||
switch d[4] {
|
||||
case 0x00:
|
||||
s.decodeFreq(payload)
|
||||
case 0x01:
|
||||
s.decodeMode(payload)
|
||||
case 0x03:
|
||||
s.decodeFreq(payload)
|
||||
case 0x04:
|
||||
s.decodeMode(payload)
|
||||
case 0x1c:
|
||||
s.decodePTT(payload)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *civDecoderStruct) decodeFreq(d []byte) {
|
||||
var f float64
|
||||
var pos int
|
||||
for _, v := range d {
|
||||
s1 := v & 0x0f
|
||||
s2 := v >> 4
|
||||
f += float64(s1) * math.Pow(10, float64(pos))
|
||||
pos++
|
||||
f += float64(s2) * math.Pow(10, float64(pos))
|
||||
pos++
|
||||
}
|
||||
statusLog.reportFrequency(f)
|
||||
}
|
||||
|
||||
func (s *civDecoderStruct) decodeMode(d []byte) {
|
||||
if len(d) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
var mode string
|
||||
switch d[0] {
|
||||
case 0x00:
|
||||
mode = "LSB"
|
||||
case 0x01:
|
||||
mode = "USB"
|
||||
case 0x02:
|
||||
mode = "AM"
|
||||
case 0x03:
|
||||
mode = "CW"
|
||||
case 0x04:
|
||||
mode = "RTTY"
|
||||
case 0x05:
|
||||
mode = "FM"
|
||||
case 0x06:
|
||||
mode = "WFM"
|
||||
case 0x07:
|
||||
mode = "CW-R"
|
||||
case 0x08:
|
||||
mode = "RTTY-R"
|
||||
case 0x17:
|
||||
mode = "DV"
|
||||
}
|
||||
|
||||
var filter string
|
||||
if len(d) > 1 {
|
||||
switch d[1] {
|
||||
case 0x01:
|
||||
filter = "FIL1"
|
||||
case 0x02:
|
||||
filter = "FIL2"
|
||||
case 0x03:
|
||||
filter = "FIL3"
|
||||
}
|
||||
}
|
||||
statusLog.reportMode(mode, filter)
|
||||
}
|
||||
|
||||
func (s *civDecoderStruct) decodePTT(d []byte) {
|
||||
if len(d) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
var ptt bool
|
||||
var tune bool
|
||||
switch d[0] {
|
||||
case 0:
|
||||
if d[1] == 1 {
|
||||
ptt = true
|
||||
}
|
||||
case 1:
|
||||
if d[1] == 2 {
|
||||
tune = true
|
||||
}
|
||||
}
|
||||
statusLog.reportPTT(ptt, tune)
|
||||
}
|
||||
|
||||
func (s *civDecoderStruct) query(st *serialStream) error {
|
||||
// Querying frequency.
|
||||
if err := st.send([]byte{254, 254, civAddress, 224, 3, 253}); err != nil {
|
||||
return err
|
||||
}
|
||||
// Querying mode.
|
||||
if err := st.send([]byte{254, 254, civAddress, 224, 4, 253}); err != nil {
|
||||
return err
|
||||
}
|
||||
// Querying PTT.
|
||||
if err := st.send([]byte{254, 254, civAddress, 224, 0x1c, 0, 253}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -338,8 +338,6 @@ func (s *controlStream) deinit() {
|
|||
log.Debug("sending deauth")
|
||||
_ = s.sendPktAuth(0x01)
|
||||
_ = s.sendPktAuth(0x01)
|
||||
_ = s.sendPktAuth(0x01)
|
||||
_ = s.sendPktAuth(0x01)
|
||||
// Waiting a little bit to make sure the radio can send retransmit requests.
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
|
|
|||
BIN
demo.gif
BIN
demo.gif
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 8.5 MiB |
2
go.mod
2
go.mod
|
|
@ -4,7 +4,9 @@ go 1.14
|
|||
|
||||
require (
|
||||
github.com/akosmarton/papipes v0.0.0-20201027113853-3c63b4919c76
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/google/goterm v0.0.0-20200907032337-555d40f16ae2
|
||||
github.com/mattn/go-isatty v0.0.11
|
||||
github.com/pborman/getopt v1.1.0
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.16.0
|
||||
|
|
|
|||
10
go.sum
10
go.sum
|
|
@ -5,6 +5,8 @@ github.com/akosmarton/papipes v0.0.0-20201027113853-3c63b4919c76/go.mod h1:mdvQ3
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/google/goterm v0.0.0-20200907032337-555d40f16ae2 h1:CVuJwN34x4xM2aT4sIKhmeib40NeBPhRihNjQmpJsA4=
|
||||
github.com/google/goterm v0.0.0-20200907032337-555d40f16ae2/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
|
|
@ -14,6 +16,11 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/pborman/getopt v1.1.0 h1:eJ3aFZroQqq0bWmraivjQNt6Dmm5M0h2JcDW38/Azb0=
|
||||
github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
|
|
@ -46,7 +53,10 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
|
|
|
|||
22
log.go
22
log.go
|
|
@ -27,13 +27,9 @@ func (l *logger) GetCallerFileName(withLine bool) string {
|
|||
}
|
||||
}
|
||||
|
||||
func (l *logger) printLineClear() {
|
||||
fmt.Printf("%c[2K", 27)
|
||||
}
|
||||
|
||||
func (l *logger) Printf(a string, b ...interface{}) {
|
||||
if statusLog.isRealtime() {
|
||||
l.printLineClear()
|
||||
statusLog.clear()
|
||||
defer statusLog.print()
|
||||
}
|
||||
l.logger.Infof(l.GetCallerFileName(false)+": "+a, b...)
|
||||
|
|
@ -41,7 +37,7 @@ func (l *logger) Printf(a string, b ...interface{}) {
|
|||
|
||||
func (l *logger) Print(a ...interface{}) {
|
||||
if statusLog.isRealtime() {
|
||||
l.printLineClear()
|
||||
statusLog.clear()
|
||||
defer statusLog.print()
|
||||
}
|
||||
l.logger.Info(append([]interface{}{l.GetCallerFileName(false) + ": "}, a...)...)
|
||||
|
|
@ -53,7 +49,7 @@ func (l *logger) PrintStatusLog(a ...interface{}) {
|
|||
|
||||
func (l *logger) Debugf(a string, b ...interface{}) {
|
||||
if statusLog.isRealtime() {
|
||||
l.printLineClear()
|
||||
statusLog.clear()
|
||||
defer statusLog.print()
|
||||
}
|
||||
l.logger.Debugf(l.GetCallerFileName(true)+": "+a, b...)
|
||||
|
|
@ -61,7 +57,7 @@ func (l *logger) Debugf(a string, b ...interface{}) {
|
|||
|
||||
func (l *logger) Debug(a ...interface{}) {
|
||||
if statusLog.isRealtime() {
|
||||
l.printLineClear()
|
||||
statusLog.clear()
|
||||
defer statusLog.print()
|
||||
}
|
||||
l.logger.Debug(append([]interface{}{l.GetCallerFileName(true) + ": "}, a...)...)
|
||||
|
|
@ -69,7 +65,7 @@ func (l *logger) Debug(a ...interface{}) {
|
|||
|
||||
func (l *logger) Errorf(a string, b ...interface{}) {
|
||||
if statusLog.isRealtime() {
|
||||
l.printLineClear()
|
||||
statusLog.clear()
|
||||
defer statusLog.print()
|
||||
}
|
||||
l.logger.Errorf(l.GetCallerFileName(true)+": "+a, b...)
|
||||
|
|
@ -77,7 +73,7 @@ func (l *logger) Errorf(a string, b ...interface{}) {
|
|||
|
||||
func (l *logger) Error(a ...interface{}) {
|
||||
if statusLog.isRealtime() {
|
||||
l.printLineClear()
|
||||
statusLog.clear()
|
||||
defer statusLog.print()
|
||||
}
|
||||
l.logger.Error(append([]interface{}{l.GetCallerFileName(true) + ": "}, a...)...)
|
||||
|
|
@ -85,7 +81,7 @@ func (l *logger) Error(a ...interface{}) {
|
|||
|
||||
func (l *logger) ErrorC(a ...interface{}) {
|
||||
if statusLog.isRealtime() {
|
||||
l.printLineClear()
|
||||
statusLog.clear()
|
||||
defer statusLog.print()
|
||||
}
|
||||
l.logger.Error(a...)
|
||||
|
|
@ -93,7 +89,7 @@ func (l *logger) ErrorC(a ...interface{}) {
|
|||
|
||||
func (l *logger) Fatalf(a string, b ...interface{}) {
|
||||
if statusLog.isRealtime() {
|
||||
l.printLineClear()
|
||||
statusLog.clear()
|
||||
defer statusLog.print()
|
||||
}
|
||||
l.logger.Fatalf(l.GetCallerFileName(true)+": "+a, b...)
|
||||
|
|
@ -101,7 +97,7 @@ func (l *logger) Fatalf(a string, b ...interface{}) {
|
|||
|
||||
func (l *logger) Fatal(a ...interface{}) {
|
||||
if statusLog.isRealtime() {
|
||||
l.printLineClear()
|
||||
statusLog.clear()
|
||||
defer statusLog.print()
|
||||
}
|
||||
l.logger.Fatal(append([]interface{}{l.GetCallerFileName(true) + ": "}, a...)...)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ type serialStream struct {
|
|||
|
||||
receivedSerialData bool
|
||||
lastReceivedSeq uint16
|
||||
civDecoder civDecoderStruct
|
||||
|
||||
readFromSerialPort struct {
|
||||
buf bytes.Buffer
|
||||
|
|
@ -92,6 +93,8 @@ func (s *serialStream) handleRxSeqBufEntry(e seqBufEntry) {
|
|||
|
||||
e.data = e.data[21:]
|
||||
|
||||
s.civDecoder.decode(e.data)
|
||||
|
||||
if serialPort.write != nil {
|
||||
serialPort.write <- e.data
|
||||
}
|
||||
|
|
@ -250,6 +253,10 @@ func (s *serialStream) init(devName string) error {
|
|||
s.readFromSerialPort.frameTimeout = time.NewTimer(0)
|
||||
<-s.readFromSerialPort.frameTimeout.C
|
||||
|
||||
if err := s.civDecoder.query(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go s.loop()
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
102
statuslog.go
102
statuslog.go
|
|
@ -2,8 +2,12 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
type statusLogStruct struct {
|
||||
|
|
@ -12,7 +16,18 @@ type statusLogStruct struct {
|
|||
stopFinishedChan chan bool
|
||||
mutex sync.Mutex
|
||||
|
||||
line string
|
||||
line1 string
|
||||
line2 string
|
||||
|
||||
state struct {
|
||||
rxStr string
|
||||
txStr string
|
||||
tuneStr string
|
||||
}
|
||||
stateStr string
|
||||
frequency float64
|
||||
mode string
|
||||
filter string
|
||||
|
||||
startTime time.Time
|
||||
rttLatency time.Duration
|
||||
|
|
@ -27,15 +42,56 @@ func (s *statusLogStruct) reportRTTLatency(l time.Duration) {
|
|||
s.rttLatency = l
|
||||
}
|
||||
|
||||
func (s *statusLogStruct) reportFrequency(f float64) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
s.frequency = f
|
||||
}
|
||||
|
||||
func (s *statusLogStruct) reportMode(mode, filter string) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
s.mode = mode
|
||||
s.filter = filter
|
||||
}
|
||||
|
||||
func (s *statusLogStruct) reportPTT(ptt, tune bool) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
if tune {
|
||||
s.stateStr = s.state.tuneStr
|
||||
} else if ptt {
|
||||
s.stateStr = s.state.txStr
|
||||
} else {
|
||||
s.stateStr = s.state.rxStr
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
if s.isRealtimeInternal() {
|
||||
log.printLineClear()
|
||||
fmt.Print(s.line)
|
||||
s.clearInternal()
|
||||
fmt.Println(s.line1)
|
||||
s.clearInternal()
|
||||
fmt.Printf(s.line2+"%c[1A", 27)
|
||||
} else {
|
||||
log.PrintStatusLog(s.line)
|
||||
log.PrintStatusLog(s.line2)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -43,15 +99,26 @@ func (s *statusLogStruct) update() {
|
|||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
up, down, lost, retransmits := netstat.get()
|
||||
var modeStr string
|
||||
if s.mode != "" {
|
||||
modeStr = " " + s.mode
|
||||
}
|
||||
var filterStr string
|
||||
if s.filter != "" {
|
||||
filterStr = " " + s.filter
|
||||
}
|
||||
s.line1 = fmt.Sprint("state ", s.stateStr, " freq: ", fmt.Sprintf("%f", s.frequency/1000000), modeStr, filterStr)
|
||||
|
||||
s.line = fmt.Sprint("up ", time.Since(s.startTime).Round(time.Second),
|
||||
up, down, lost, retransmits := netstat.get()
|
||||
s.line2 = fmt.Sprint("up ", time.Since(s.startTime).Round(time.Second),
|
||||
" rtt ", s.rttLatency.Milliseconds(), "ms up ",
|
||||
netstat.formatByteCount(up), "/s down ",
|
||||
netstat.formatByteCount(down), "/s retx ", retransmits, " /1m lost ", lost, " /1m")
|
||||
netstat.formatByteCount(down), "/s retx ", retransmits, " /1m lost ", lost, " /1m\r")
|
||||
|
||||
if s.isRealtimeInternal() {
|
||||
s.line = fmt.Sprint(time.Now().Format("2006-01-02T15:04:05.000Z0700"), " ", s.line, "\r")
|
||||
t := time.Now().Format("2006-01-02T15:04:05.000Z0700")
|
||||
s.line1 = fmt.Sprint(t, " ", s.line1)
|
||||
s.line2 = fmt.Sprint(t, " ", s.line2)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +157,21 @@ func (s *statusLogStruct) startPeriodicPrint() {
|
|||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
if !isatty.IsTerminal(os.Stdout.Fd()) && statusLogInterval < time.Second {
|
||||
statusLogInterval = time.Second
|
||||
}
|
||||
|
||||
c := color.New(color.FgHiWhite)
|
||||
c.Add(color.BgWhite)
|
||||
s.stateStr = c.Sprint(" ?? ")
|
||||
c = color.New(color.FgHiWhite)
|
||||
c.Add(color.BgGreen)
|
||||
s.state.rxStr = c.Sprint(" RX ")
|
||||
c = color.New(color.FgHiWhite, color.BlinkRapid)
|
||||
c.Add(color.BgRed)
|
||||
s.state.txStr = c.Sprint(" TX ")
|
||||
s.state.tuneStr = c.Sprint(" TUNE ")
|
||||
|
||||
s.startTime = time.Now()
|
||||
s.stopChan = make(chan bool)
|
||||
s.stopFinishedChan = make(chan bool)
|
||||
|
|
@ -106,4 +188,8 @@ func (s *statusLogStruct) stopPeriodicPrint() {
|
|||
|
||||
s.stopChan <- true
|
||||
<-s.stopFinishedChan
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println()
|
||||
fmt.Println()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue