Add support for displaying/adjusting the tuning step

This commit is contained in:
Nonoo 2020-11-04 09:06:32 +01:00
parent 70609960a6
commit b7c79a2bd4
4 changed files with 138 additions and 90 deletions

View file

@ -85,8 +85,12 @@ kappanhang displays a "realtime" status bar (when the audio/serial connection
is up) with the following info:
- First status bar line:
- `S meter`: periodically refreshed S meter value
- Second status bar line:
- `state`: RX/TX/TUNE depending on the PTT status
- `freq`: operating frequency in MHz
- `ts`: tuning step
- `mode`: LSB/USB/FM etc.
- `filter`: active filter (FIL1, FIL2 etc.)
- `preamp`: PAMP0 means the preamp is off
@ -94,9 +98,8 @@ is up) with the following info:
- `txpwr`: current transmit power setting in percent
- `audio`: current status of the audio monitor (see the *Hotkeys* section
in this README for more information about this feature)
- `S meter`: periodically refreshed S meter value
- Second status bar line:
- Third 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
@ -104,8 +107,8 @@ is up) with the following info:
- `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.
Data for the first 2 status bar lines are acquired by monitoring CiV traffic
in the serial stream. S value is queried periodically.
`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
@ -116,7 +119,7 @@ audio and serial communication disruptions.
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
disabled and the contents of the last 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.
@ -135,12 +138,8 @@ Some basic CAT control hotkeys are also supported:
- `t`: toggles the tune process
- `+`: increases TX power
- `-`: decreases TX power
- `<`, `>`: decreases, increases frequency 1Hz
- `,`, `.`: decreases, increases frequency 10Hz
- `:`, `"`: decreases, increases frequency 100Hz
- `;`, `'`: decreases, increases frequency 1kHz
- `{`, `}`: decreases, increases frequency 10kHz
- `[`, `]`: decreases, increases frequency 100kHz
- `[`, `]`: decreases, increases frequency
- `{`, `}`: decreases, increases tuning step
- `n`, `m`: cycles through operating modes
- `d`, `f`: cycles through filters
- `D`: toggles data mode

View file

@ -79,6 +79,8 @@ type civControlStruct struct {
bandIdx int
bandChanging bool
preamp int
tsValue byte
ts uint
}
}
@ -100,6 +102,8 @@ func (s *civControlStruct) decode(d []byte) {
s.decodeFreq(payload)
case 0x04:
s.decodeMode(payload)
case 0x10:
s.decodeTS(payload)
case 0x1a:
s.decodeDataMode(payload)
case 0x14:
@ -174,6 +178,46 @@ func (s *civControlStruct) decodeMode(d []byte) {
_ = s.getDataMode()
}
func (s *civControlStruct) decodeTS(d []byte) {
if len(d) < 1 {
return
}
s.state.tsValue = d[0]
switch s.state.tsValue {
default:
s.state.ts = 1
case 1:
s.state.ts = 100
case 2:
s.state.ts = 500
case 3:
s.state.ts = 1000
case 4:
s.state.ts = 5000
case 5:
s.state.ts = 6250
case 6:
s.state.ts = 8330
case 7:
s.state.ts = 9000
case 8:
s.state.ts = 10000
case 9:
s.state.ts = 12500
case 10:
s.state.ts = 20000
case 11:
s.state.ts = 25000
case 12:
s.state.ts = 50000
case 13:
s.state.ts = 100000
}
statusLog.reportTS(s.state.ts)
}
func (s *civControlStruct) decodeDataMode(d []byte) {
if len(d) < 3 || d[0] != 0x06 {
return
@ -304,12 +348,12 @@ func (s *civControlStruct) getDigit(v uint, n int) byte {
return byte(uint(f) % 10)
}
func (s *civControlStruct) incFreq(v uint) error {
return s.setFreq(s.state.freq + v)
func (s *civControlStruct) incFreq() error {
return s.setFreq(s.state.freq + s.state.ts)
}
func (s *civControlStruct) decFreq(v uint) error {
return s.setFreq(s.state.freq - v)
func (s *civControlStruct) decFreq() error {
return s.setFreq(s.state.freq - s.state.ts)
}
func (s *civControlStruct) setFreq(f uint) error {
@ -448,6 +492,26 @@ func (s *civControlStruct) togglePreamp() error {
return s.st.send([]byte{254, 254, civAddress, 224, 0x16, 0x02, b, 253})
}
func (s *civControlStruct) incTS() error {
var b byte
if s.state.tsValue == 13 {
b = 0
} else {
b = s.state.tsValue + 1
}
return s.st.send([]byte{254, 254, civAddress, 224, 0x10, b, 253})
}
func (s *civControlStruct) decTS() error {
var b byte
if s.state.tsValue == 0 {
b = 13
} else {
b = s.state.tsValue - 1
}
return s.st.send([]byte{254, 254, civAddress, 224, 0x10, b, 253})
}
func (s *civControlStruct) getFreq() error {
return s.st.send([]byte{254, 254, civAddress, 224, 3, 253})
}
@ -475,6 +539,10 @@ func (s *civControlStruct) getS() error {
return s.st.send([]byte{254, 254, civAddress, 224, 0x15, 0x02, 253})
}
func (s *civControlStruct) getTS() error {
return s.st.send([]byte{254, 254, civAddress, 224, 0x10, 253})
}
func (s *civControlStruct) loop() {
for {
select {
@ -517,6 +585,9 @@ func (s *civControlStruct) init(st *serialStream) error {
if err := s.getS(); err != nil {
return err
}
if err := s.getTS(); err != nil {
return err
}
s.deinitNeeded = make(chan bool)
s.deinitFinished = make(chan bool)

View file

@ -24,78 +24,30 @@ func handleHotkey(k byte) {
log.Error("can't decrease power: ", err)
}
}
case '>':
if civControl != nil {
if err := civControl.incFreq(1); err != nil {
log.Error("can't increase freq: ", err)
}
}
case '<':
if civControl != nil {
if err := civControl.decFreq(1); err != nil {
log.Error("can't decrease freq: ", err)
}
}
case '.':
if civControl != nil {
if err := civControl.incFreq(10); err != nil {
log.Error("can't increase freq: ", err)
}
}
case ',':
if civControl != nil {
if err := civControl.decFreq(10); err != nil {
log.Error("can't decrease freq: ", err)
}
}
case '"':
if civControl != nil {
if err := civControl.incFreq(100); err != nil {
log.Error("can't increase freq: ", err)
}
}
case ':':
if civControl != nil {
if err := civControl.decFreq(100); err != nil {
log.Error("can't decrease freq: ", err)
}
}
case '\'':
if civControl != nil {
if err := civControl.incFreq(1000); err != nil {
log.Error("can't increase freq: ", err)
}
}
case ';':
if civControl != nil {
if err := civControl.decFreq(1000); err != nil {
log.Error("can't decrease freq: ", err)
}
}
case '}':
if civControl != nil {
if err := civControl.incFreq(10000); err != nil {
log.Error("can't increase freq: ", err)
}
}
case '{':
if civControl != nil {
if err := civControl.decFreq(10000); err != nil {
log.Error("can't decrease freq: ", err)
}
}
case ']':
if civControl != nil {
if err := civControl.incFreq(100000); err != nil {
if err := civControl.incFreq(); err != nil {
log.Error("can't increase freq: ", err)
}
}
case '[':
if civControl != nil {
if err := civControl.decFreq(100000); err != nil {
if err := civControl.decFreq(); err != nil {
log.Error("can't decrease freq: ", err)
}
}
case '}':
if civControl != nil {
if err := civControl.incTS(); err != nil {
log.Error("can't increase ts: ", err)
}
}
case '{':
if civControl != nil {
if err := civControl.decTS(); err != nil {
log.Error("can't decrease ts: ", err)
}
}
case 'm':
if civControl != nil {
if err := civControl.incOperatingMode(); err != nil {

View file

@ -15,15 +15,16 @@ type statusLogData struct {
line2 string
line3 string
stateStr string
frequency uint
mode string
dataMode string
filter string
preamp string
vd string
txPowerStr string
s string
stateStr string
frequency uint
mode string
dataMode string
filter string
preamp string
vd string
txPower string
s string
ts string
startTime time.Time
rttStr string
@ -167,6 +168,27 @@ func (s *statusLogStruct) reportS(sValue string) {
s.data.s = sValue
}
func (s *statusLogStruct) reportTS(ts uint) {
s.mutex.Lock()
defer s.mutex.Unlock()
if s.data == nil {
return
}
s.data.ts = "TS"
if ts >= 1000 {
if ts%1000 == 0 {
s.data.ts += fmt.Sprintf("%.0fk", float64(ts)/1000)
} else if ts%100 == 0 {
s.data.ts += fmt.Sprintf("%.1fk", float64(ts)/1000)
} else {
s.data.ts += fmt.Sprintf("%.2fk", float64(ts)/1000)
}
} else {
s.data.ts += fmt.Sprint(ts)
}
}
func (s *statusLogStruct) reportPTT(ptt, tune bool) {
s.mutex.Lock()
defer s.mutex.Unlock()
@ -190,7 +212,7 @@ func (s *statusLogStruct) reportTxPower(percent int) {
if s.data == nil {
return
}
s.data.txPowerStr = fmt.Sprint(percent, "%")
s.data.txPower = fmt.Sprint(percent, "%")
}
func (s *statusLogStruct) clearInternal() {
@ -229,6 +251,10 @@ func (s *statusLogStruct) update() {
s.data.line1 = fmt.Sprint(s.data.s)
var tsStr string
if s.data.ts != "" {
tsStr = " " + s.data.ts
}
var modeStr string
if s.data.mode != "" {
modeStr = " " + s.data.mode + s.data.dataMode
@ -246,11 +272,11 @@ func (s *statusLogStruct) update() {
vdStr = " " + s.data.vd
}
var txPowerStr string
if s.data.txPowerStr != "" {
txPowerStr = " txpwr " + s.data.txPowerStr
if s.data.txPower != "" {
txPowerStr = " txpwr " + s.data.txPower
}
s.data.line2 = fmt.Sprint(s.data.stateStr, " ", fmt.Sprintf("%.6f", float64(s.data.frequency)/1000000),
modeStr, filterStr, preampStr, vdStr, txPowerStr, " audio ", s.data.audioStateStr)
tsStr, modeStr, filterStr, preampStr, vdStr, txPowerStr, " audio ", s.data.audioStateStr)
up, down, lost, retransmits := netstat.get()
lostStr := "0"