2020-10-29 09:39:13 +01:00
|
|
|
package main
|
|
|
|
|
|
2020-10-30 22:58:31 +01:00
|
|
|
import (
|
2020-11-03 22:06:51 +01:00
|
|
|
"fmt"
|
2020-10-30 22:58:31 +01:00
|
|
|
"math"
|
2020-11-08 20:48:39 +01:00
|
|
|
"sync"
|
2020-10-30 22:58:31 +01:00
|
|
|
"time"
|
|
|
|
|
)
|
2020-10-29 09:39:13 +01:00
|
|
|
|
|
|
|
|
const civAddress = 0xa4
|
2020-11-09 09:40:18 +01:00
|
|
|
const statusPollInterval = time.Second
|
|
|
|
|
const commandRetryTimeout = 500 * time.Millisecond
|
2020-10-29 09:39:13 +01:00
|
|
|
|
2020-11-05 08:19:16 +01:00
|
|
|
// Commands reference: https://www.icomeurope.com/wp-content/uploads/2020/08/IC-705_ENG_CI-V_1_20200721.pdf
|
|
|
|
|
|
2020-10-31 14:07:02 +01:00
|
|
|
type civOperatingMode struct {
|
|
|
|
|
name string
|
|
|
|
|
code byte
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var civOperatingModes = []civOperatingMode{
|
|
|
|
|
{name: "LSB", code: 0x00},
|
|
|
|
|
{name: "USB", code: 0x01},
|
|
|
|
|
{name: "AM", code: 0x02},
|
|
|
|
|
{name: "CW", code: 0x03},
|
|
|
|
|
{name: "RTTY", code: 0x04},
|
|
|
|
|
{name: "FM", code: 0x05},
|
|
|
|
|
{name: "WFM", code: 0x06},
|
|
|
|
|
{name: "CW-R", code: 0x07},
|
|
|
|
|
{name: "RTTY-R", code: 0x08},
|
|
|
|
|
{name: "DV", code: 0x17},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type civFilter struct {
|
|
|
|
|
name string
|
|
|
|
|
code byte
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var civFilters = []civFilter{
|
|
|
|
|
{name: "FIL1", code: 0x01},
|
|
|
|
|
{name: "FIL2", code: 0x02},
|
|
|
|
|
{name: "FIL3", code: 0x03},
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-31 23:44:45 +01:00
|
|
|
type civBand struct {
|
2020-11-01 12:46:37 +01:00
|
|
|
freqFrom uint
|
|
|
|
|
freqTo uint
|
|
|
|
|
freq uint
|
2020-10-31 23:44:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var civBands = []civBand{
|
2020-11-01 12:46:37 +01:00
|
|
|
{freqFrom: 1800000, freqTo: 1999999}, // 1.9
|
|
|
|
|
{freqFrom: 3400000, freqTo: 4099999}, // 3.5
|
|
|
|
|
{freqFrom: 6900000, freqTo: 7499999}, // 7
|
|
|
|
|
{freqFrom: 9900000, freqTo: 10499999}, // 10
|
|
|
|
|
{freqFrom: 13900000, freqTo: 14499999}, // 14
|
|
|
|
|
{freqFrom: 17900000, freqTo: 18499999}, // 18
|
|
|
|
|
{freqFrom: 20900000, freqTo: 21499999}, // 21
|
|
|
|
|
{freqFrom: 24400000, freqTo: 25099999}, // 24
|
|
|
|
|
{freqFrom: 28000000, freqTo: 29999999}, // 28
|
|
|
|
|
{freqFrom: 50000000, freqTo: 54000000}, // 50
|
|
|
|
|
{freqFrom: 74800000, freqTo: 107999999}, // WFM
|
|
|
|
|
{freqFrom: 108000000, freqTo: 136999999}, // AIR
|
|
|
|
|
{freqFrom: 144000000, freqTo: 148000000}, // 144
|
|
|
|
|
{freqFrom: 420000000, freqTo: 450000000}, // 430
|
|
|
|
|
{freqFrom: 0, freqTo: 0}, // GENE
|
2020-10-31 23:44:45 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-07 18:09:09 +01:00
|
|
|
type splitMode int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
splitModeOff = iota
|
|
|
|
|
splitModeOn
|
|
|
|
|
splitModeDUPMinus
|
|
|
|
|
splitModeDUPPlus
|
|
|
|
|
)
|
|
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
type civCmd struct {
|
|
|
|
|
pending bool
|
|
|
|
|
sentAt time.Time
|
|
|
|
|
name string
|
|
|
|
|
cmd []byte
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 20:28:45 +01:00
|
|
|
type civControlStruct struct {
|
2020-11-09 09:40:18 +01:00
|
|
|
st *serialStream
|
|
|
|
|
deinitNeeded chan bool
|
|
|
|
|
deinitFinished chan bool
|
|
|
|
|
resetSReadTimer chan bool
|
|
|
|
|
newPendingCmdAdded chan bool
|
2020-10-30 22:58:31 +01:00
|
|
|
|
|
|
|
|
state struct {
|
2020-11-09 09:40:18 +01:00
|
|
|
mutex sync.Mutex
|
|
|
|
|
pendingCmds []*civCmd
|
|
|
|
|
|
|
|
|
|
getFreq civCmd
|
|
|
|
|
getMode civCmd
|
|
|
|
|
getDataMode civCmd
|
|
|
|
|
getPwr civCmd
|
|
|
|
|
getS civCmd
|
|
|
|
|
getOVF civCmd
|
|
|
|
|
getSWR civCmd
|
|
|
|
|
getTransmitStatus civCmd
|
|
|
|
|
getPreamp civCmd
|
|
|
|
|
getAGC civCmd
|
|
|
|
|
getTuneStatus civCmd
|
|
|
|
|
getVd civCmd
|
|
|
|
|
getTS civCmd
|
|
|
|
|
getRFGain civCmd
|
|
|
|
|
getSQL civCmd
|
|
|
|
|
getNR civCmd
|
|
|
|
|
getNREnabled civCmd
|
|
|
|
|
getSplit civCmd
|
2020-11-04 12:06:12 +01:00
|
|
|
|
2020-11-06 16:22:38 +01:00
|
|
|
lastSReceivedAt time.Time
|
|
|
|
|
lastOVFReceivedAt time.Time
|
|
|
|
|
lastSWRReceivedAt time.Time
|
|
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
setPwr civCmd
|
|
|
|
|
setRFGain civCmd
|
|
|
|
|
setSQL civCmd
|
|
|
|
|
setNR civCmd
|
|
|
|
|
setFreq civCmd
|
|
|
|
|
setMode civCmd
|
|
|
|
|
setPTT civCmd
|
|
|
|
|
setTune civCmd
|
|
|
|
|
setDataMode civCmd
|
|
|
|
|
setPreamp civCmd
|
|
|
|
|
setAGC civCmd
|
|
|
|
|
setNREnabled civCmd
|
|
|
|
|
setTS civCmd
|
|
|
|
|
setVFO civCmd
|
|
|
|
|
setSplit civCmd
|
2020-11-08 20:48:39 +01:00
|
|
|
|
2020-11-01 12:46:37 +01:00
|
|
|
freq uint
|
2020-10-31 14:07:02 +01:00
|
|
|
ptt bool
|
|
|
|
|
tune bool
|
|
|
|
|
pwrPercent int
|
2020-11-04 09:41:36 +01:00
|
|
|
rfGainPercent int
|
2020-11-04 09:47:41 +01:00
|
|
|
sqlPercent int
|
2020-11-04 10:01:07 +01:00
|
|
|
nrPercent int
|
|
|
|
|
nrEnabled bool
|
2020-10-31 14:07:02 +01:00
|
|
|
operatingModeIdx int
|
|
|
|
|
filterIdx int
|
|
|
|
|
dataMode bool
|
2020-10-31 23:44:45 +01:00
|
|
|
bandIdx int
|
|
|
|
|
bandChanging bool
|
2020-11-03 16:19:37 +01:00
|
|
|
preamp int
|
2020-11-05 08:19:16 +01:00
|
|
|
agc int
|
2020-11-04 09:06:32 +01:00
|
|
|
tsValue byte
|
|
|
|
|
ts uint
|
2020-11-07 16:25:31 +01:00
|
|
|
vfoBActive bool
|
2020-11-07 18:09:09 +01:00
|
|
|
splitMode splitMode
|
2020-10-30 22:58:31 +01:00
|
|
|
}
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-30 22:12:30 +01:00
|
|
|
var civControl *civControlStruct
|
|
|
|
|
|
2020-11-04 10:18:32 +01:00
|
|
|
// Returns false if the message should not be forwarded to the serial port TCP server or the virtual serial port.
|
|
|
|
|
func (s *civControlStruct) decode(d []byte) bool {
|
2020-10-29 09:39:13 +01:00
|
|
|
if len(d) < 6 || d[0] != 0xfe || d[1] != 0xfe || d[len(d)-1] != 0xfd {
|
2020-11-04 10:18:32 +01:00
|
|
|
return true
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
payload := d[5 : len(d)-1]
|
|
|
|
|
|
2020-11-08 20:48:39 +01:00
|
|
|
s.state.mutex.Lock()
|
|
|
|
|
defer s.state.mutex.Unlock()
|
|
|
|
|
|
2020-10-29 09:39:13 +01:00
|
|
|
switch d[4] {
|
|
|
|
|
case 0x00:
|
2020-11-04 12:06:12 +01:00
|
|
|
return s.decodeFreq(payload)
|
2020-10-29 09:39:13 +01:00
|
|
|
case 0x01:
|
2020-11-04 12:06:12 +01:00
|
|
|
return s.decodeMode(payload)
|
2020-10-29 09:39:13 +01:00
|
|
|
case 0x03:
|
2020-11-04 12:06:12 +01:00
|
|
|
return s.decodeFreq(payload)
|
2020-10-29 09:39:13 +01:00
|
|
|
case 0x04:
|
2020-11-04 12:06:12 +01:00
|
|
|
return s.decodeMode(payload)
|
|
|
|
|
case 0x05:
|
|
|
|
|
return s.decodeFreq(payload)
|
|
|
|
|
case 0x06:
|
|
|
|
|
return s.decodeMode(payload)
|
2020-11-07 16:25:31 +01:00
|
|
|
case 0x07:
|
|
|
|
|
return s.decodeVFO(payload)
|
2020-11-07 18:09:09 +01:00
|
|
|
case 0x0f:
|
|
|
|
|
return s.decodeSplit(payload)
|
2020-11-04 09:06:32 +01:00
|
|
|
case 0x10:
|
2020-11-04 12:06:12 +01:00
|
|
|
return s.decodeTS(payload)
|
2020-10-30 22:58:31 +01:00
|
|
|
case 0x1a:
|
2020-11-04 10:18:32 +01:00
|
|
|
return s.decodeDataModeAndOVF(payload)
|
2020-10-30 14:55:25 +01:00
|
|
|
case 0x14:
|
2020-11-09 09:40:18 +01:00
|
|
|
return s.decodePowerRFGainSQLNRPwr(payload)
|
2020-10-29 09:39:13 +01:00
|
|
|
case 0x1c:
|
2020-11-04 12:06:12 +01:00
|
|
|
return s.decodeTransmitStatus(payload)
|
2020-11-03 16:35:23 +01:00
|
|
|
case 0x15:
|
2020-11-04 10:41:12 +01:00
|
|
|
return s.decodeVdSWRS(payload)
|
2020-11-03 16:19:37 +01:00
|
|
|
case 0x16:
|
2020-11-09 09:40:18 +01:00
|
|
|
return s.decodePreampAGCNREnabled(payload)
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
2020-11-04 10:18:32 +01:00
|
|
|
return true
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 12:06:12 +01:00
|
|
|
func (s *civControlStruct) decodeFreq(d []byte) bool {
|
|
|
|
|
if len(d) < 2 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getFreq.pending && !s.state.setFreq.pending
|
2020-11-04 12:06:12 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-01 12:46:37 +01:00
|
|
|
var f uint
|
2020-10-29 09:39:13 +01:00
|
|
|
var pos int
|
|
|
|
|
for _, v := range d {
|
|
|
|
|
s1 := v & 0x0f
|
|
|
|
|
s2 := v >> 4
|
2020-11-01 12:46:37 +01:00
|
|
|
f += uint(s1) * uint(math.Pow(10, float64(pos)))
|
2020-10-29 09:39:13 +01:00
|
|
|
pos++
|
2020-11-01 12:46:37 +01:00
|
|
|
f += uint(s2) * uint(math.Pow(10, float64(pos)))
|
2020-10-29 09:39:13 +01:00
|
|
|
pos++
|
|
|
|
|
}
|
2020-11-04 12:06:12 +01:00
|
|
|
|
2020-11-01 12:46:37 +01:00
|
|
|
s.state.freq = f
|
2020-10-30 23:58:10 +01:00
|
|
|
statusLog.reportFrequency(s.state.freq)
|
2020-10-31 23:44:45 +01:00
|
|
|
|
|
|
|
|
s.state.bandIdx = len(civBands) - 1 // Set the band idx to GENE by default.
|
|
|
|
|
for i := range civBands {
|
|
|
|
|
if s.state.freq >= civBands[i].freqFrom && s.state.freq <= civBands[i].freqTo {
|
|
|
|
|
s.state.bandIdx = i
|
|
|
|
|
civBands[s.state.bandIdx].freq = s.state.freq
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-04 12:06:12 +01:00
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getFreq.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getFreq)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.setFreq.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setFreq)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-31 14:07:02 +01:00
|
|
|
func (s *civControlStruct) decodeFilterValueToFilterIdx(v byte) int {
|
|
|
|
|
for i := range civFilters {
|
|
|
|
|
if civFilters[i].code == v {
|
|
|
|
|
return i
|
|
|
|
|
}
|
2020-10-30 22:58:31 +01:00
|
|
|
}
|
2020-10-31 14:07:02 +01:00
|
|
|
return -1
|
2020-10-30 22:58:31 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 12:06:12 +01:00
|
|
|
func (s *civControlStruct) decodeMode(d []byte) bool {
|
2020-10-29 09:39:13 +01:00
|
|
|
if len(d) < 1 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getMode.pending && !s.state.setMode.pending
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var mode string
|
2020-10-31 14:07:02 +01:00
|
|
|
for i := range civOperatingModes {
|
|
|
|
|
if civOperatingModes[i].code == d[0] {
|
|
|
|
|
s.state.operatingModeIdx = i
|
|
|
|
|
mode = civOperatingModes[i].name
|
|
|
|
|
break
|
|
|
|
|
}
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var filter string
|
|
|
|
|
if len(d) > 1 {
|
2020-10-31 14:07:02 +01:00
|
|
|
s.state.filterIdx = s.decodeFilterValueToFilterIdx(d[1])
|
|
|
|
|
filter = civFilters[s.state.filterIdx].name
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
statusLog.reportMode(mode, filter)
|
2020-10-30 22:58:31 +01:00
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getMode.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getMode)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.setMode.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setMode)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
2020-10-30 22:58:31 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-07 16:25:31 +01:00
|
|
|
func (s *civControlStruct) decodeVFO(d []byte) bool {
|
|
|
|
|
if len(d) < 1 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.setVFO.pending
|
2020-11-07 16:25:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if d[0] == 1 {
|
|
|
|
|
s.state.vfoBActive = true
|
|
|
|
|
log.Print("active vfo: B")
|
|
|
|
|
} else {
|
|
|
|
|
s.state.vfoBActive = false
|
|
|
|
|
log.Print("active vfo: A")
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.setVFO.pending {
|
2020-11-07 16:25:31 +01:00
|
|
|
// The radio does not send the VFO's frequency automatically.
|
|
|
|
|
_ = s.getFreq()
|
|
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
s.removePendingCmd(&s.state.setVFO)
|
2020-11-07 16:25:31 +01:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-07 18:09:09 +01:00
|
|
|
func (s *civControlStruct) decodeSplit(d []byte) bool {
|
|
|
|
|
if len(d) < 1 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getSplit.pending && !s.state.setSplit.pending
|
2020-11-07 18:09:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var str string
|
|
|
|
|
switch d[0] {
|
|
|
|
|
default:
|
|
|
|
|
s.state.splitMode = splitModeOff
|
|
|
|
|
case 0x01:
|
|
|
|
|
s.state.splitMode = splitModeOn
|
|
|
|
|
str = "SPLIT"
|
|
|
|
|
case 0x11:
|
|
|
|
|
s.state.splitMode = splitModeDUPMinus
|
|
|
|
|
str = "DUP-"
|
|
|
|
|
case 0x12:
|
|
|
|
|
s.state.splitMode = splitModeDUPPlus
|
|
|
|
|
str = "DUP+"
|
|
|
|
|
}
|
|
|
|
|
statusLog.reportSplit(str)
|
|
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getSplit.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getSplit)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.setSplit.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setSplit)
|
2020-11-07 18:09:09 +01:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 12:06:12 +01:00
|
|
|
func (s *civControlStruct) decodeTS(d []byte) bool {
|
2020-11-04 09:06:32 +01:00
|
|
|
if len(d) < 1 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getTS.pending && !s.state.setTS.pending
|
2020-11-04 09:06:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getTS.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getTS)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.setTS.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setTS)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
2020-10-30 22:58:31 +01:00
|
|
|
}
|
2020-11-04 12:06:12 +01:00
|
|
|
return true
|
|
|
|
|
}
|
2020-10-30 22:58:31 +01:00
|
|
|
|
2020-11-04 12:06:12 +01:00
|
|
|
func (s *civControlStruct) decodeDataModeAndOVF(d []byte) bool {
|
2020-11-04 09:18:48 +01:00
|
|
|
switch d[0] {
|
|
|
|
|
case 0x06:
|
|
|
|
|
if len(d) < 3 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getDataMode.pending && !s.state.setDataMode.pending
|
2020-11-04 09:18:48 +01:00
|
|
|
}
|
|
|
|
|
var dataMode string
|
|
|
|
|
var filter string
|
|
|
|
|
if d[1] == 1 {
|
|
|
|
|
dataMode = "-D"
|
|
|
|
|
s.state.dataMode = true
|
|
|
|
|
s.state.filterIdx = s.decodeFilterValueToFilterIdx(d[2])
|
|
|
|
|
filter = civFilters[s.state.filterIdx].name
|
|
|
|
|
} else {
|
|
|
|
|
s.state.dataMode = false
|
|
|
|
|
}
|
2020-10-30 22:58:31 +01:00
|
|
|
|
2020-11-04 09:18:48 +01:00
|
|
|
statusLog.reportDataMode(dataMode, filter)
|
2020-11-04 12:06:12 +01:00
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getDataMode.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getDataMode)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.setDataMode.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setDataMode)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-04 09:18:48 +01:00
|
|
|
case 0x09:
|
2020-11-04 10:18:32 +01:00
|
|
|
if len(d) < 2 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getOVF.pending
|
2020-11-04 10:18:32 +01:00
|
|
|
}
|
2020-11-04 09:18:48 +01:00
|
|
|
if d[1] != 0 {
|
|
|
|
|
statusLog.reportOVF(true)
|
|
|
|
|
} else {
|
|
|
|
|
statusLog.reportOVF(false)
|
|
|
|
|
}
|
2020-11-06 16:22:38 +01:00
|
|
|
s.state.lastOVFReceivedAt = time.Now()
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getOVF.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getOVF)
|
2020-11-04 10:18:32 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-04 09:18:48 +01:00
|
|
|
}
|
2020-11-04 10:18:32 +01:00
|
|
|
return true
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
func (s *civControlStruct) decodePowerRFGainSQLNRPwr(d []byte) bool {
|
2020-11-04 09:41:36 +01:00
|
|
|
switch d[0] {
|
|
|
|
|
case 0x02:
|
2020-11-04 12:06:12 +01:00
|
|
|
if len(d) < 3 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getRFGain.pending && !s.state.setRFGain.pending
|
2020-11-04 12:06:12 +01:00
|
|
|
}
|
2020-11-04 09:41:36 +01:00
|
|
|
hex := uint16(d[1])<<8 | uint16(d[2])
|
|
|
|
|
s.state.rfGainPercent = int(math.Round((float64(hex) / 0x0255) * 100))
|
|
|
|
|
statusLog.reportRFGain(s.state.rfGainPercent)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getRFGain.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getRFGain)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.setRFGain.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setRFGain)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-04 09:47:41 +01:00
|
|
|
case 0x03:
|
2020-11-04 12:06:12 +01:00
|
|
|
if len(d) < 3 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getSQL.pending && !s.state.setSQL.pending
|
2020-11-04 12:06:12 +01:00
|
|
|
}
|
2020-11-04 09:47:41 +01:00
|
|
|
hex := uint16(d[1])<<8 | uint16(d[2])
|
|
|
|
|
s.state.sqlPercent = int(math.Round((float64(hex) / 0x0255) * 100))
|
|
|
|
|
statusLog.reportSQL(s.state.sqlPercent)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getSQL.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getSQL)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.setSQL.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setSQL)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-04 10:01:07 +01:00
|
|
|
case 0x06:
|
2020-11-04 12:06:12 +01:00
|
|
|
if len(d) < 3 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getNR.pending && !s.state.setNR.pending
|
2020-11-04 12:06:12 +01:00
|
|
|
}
|
2020-11-04 10:01:07 +01:00
|
|
|
hex := uint16(d[1])<<8 | uint16(d[2])
|
|
|
|
|
s.state.nrPercent = int(math.Round((float64(hex) / 0x0255) * 100))
|
|
|
|
|
statusLog.reportNR(s.state.nrPercent)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getNR.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getNR)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.setNR.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setNR)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-04 09:41:36 +01:00
|
|
|
case 0x0a:
|
2020-11-04 12:06:12 +01:00
|
|
|
if len(d) < 3 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getPwr.pending && !s.state.setPwr.pending
|
2020-11-04 12:06:12 +01:00
|
|
|
}
|
2020-11-04 09:41:36 +01:00
|
|
|
hex := uint16(d[1])<<8 | uint16(d[2])
|
|
|
|
|
s.state.pwrPercent = int(math.Round((float64(hex) / 0x0255) * 100))
|
|
|
|
|
statusLog.reportTxPower(s.state.pwrPercent)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getPwr.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getPwr)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.setPwr.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setPwr)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-04 09:41:36 +01:00
|
|
|
}
|
2020-11-04 12:06:12 +01:00
|
|
|
return true
|
2020-10-30 14:55:25 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 12:06:12 +01:00
|
|
|
func (s *civControlStruct) decodeTransmitStatus(d []byte) bool {
|
2020-10-29 09:39:13 +01:00
|
|
|
if len(d) < 2 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getTuneStatus.pending && !s.state.getTransmitStatus.pending && !s.state.setPTT.pending
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch d[0] {
|
|
|
|
|
case 0:
|
|
|
|
|
if d[1] == 1 {
|
2020-10-30 22:58:31 +01:00
|
|
|
s.state.ptt = true
|
|
|
|
|
} else {
|
2020-11-03 16:49:48 +01:00
|
|
|
if s.state.ptt { // PTT released?
|
|
|
|
|
s.state.ptt = false
|
|
|
|
|
_ = s.getVd()
|
|
|
|
|
}
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
2020-11-04 12:06:12 +01:00
|
|
|
statusLog.reportPTT(s.state.ptt, s.state.tune)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.setPTT.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setPTT)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-10-29 09:39:13 +01:00
|
|
|
case 1:
|
|
|
|
|
if d[1] == 2 {
|
2020-10-30 22:58:31 +01:00
|
|
|
s.state.tune = true
|
|
|
|
|
|
|
|
|
|
// The transceiver does not send the tune state after it's finished.
|
|
|
|
|
time.AfterFunc(time.Second, func() {
|
|
|
|
|
_ = s.getTransmitStatus()
|
|
|
|
|
})
|
|
|
|
|
} else {
|
2020-11-03 16:49:48 +01:00
|
|
|
if s.state.tune { // Tune finished?
|
|
|
|
|
s.state.tune = false
|
|
|
|
|
_ = s.getVd()
|
|
|
|
|
}
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
2020-11-04 12:06:12 +01:00
|
|
|
|
|
|
|
|
statusLog.reportPTT(s.state.ptt, s.state.tune)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.setTune.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setTune)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
|
|
|
|
|
if s.state.getTuneStatus.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getTuneStatus)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.getTransmitStatus.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getTransmitStatus)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
2020-10-29 09:39:13 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 10:41:12 +01:00
|
|
|
func (s *civControlStruct) decodeVdSWRS(d []byte) bool {
|
2020-11-03 16:35:23 +01:00
|
|
|
switch d[0] {
|
2020-11-03 20:55:27 +01:00
|
|
|
case 0x02:
|
2020-11-04 10:18:32 +01:00
|
|
|
if len(d) < 3 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getS.pending
|
2020-11-04 10:18:32 +01:00
|
|
|
}
|
2020-11-03 22:06:51 +01:00
|
|
|
sValue := (int(math.Round(((float64(int(d[1])<<8) + float64(d[2])) / 0x0241) * 18)))
|
|
|
|
|
sStr := "S"
|
|
|
|
|
if sValue <= 9 {
|
|
|
|
|
sStr += fmt.Sprint(sValue)
|
|
|
|
|
} else {
|
|
|
|
|
sStr += "9+"
|
|
|
|
|
|
2020-11-04 09:31:46 +01:00
|
|
|
switch sValue {
|
|
|
|
|
case 10:
|
|
|
|
|
sStr += "10"
|
|
|
|
|
case 11:
|
|
|
|
|
sStr += "20"
|
|
|
|
|
case 12:
|
|
|
|
|
sStr += "30"
|
|
|
|
|
case 13:
|
|
|
|
|
sStr += "40"
|
|
|
|
|
case 14:
|
|
|
|
|
sStr += "40"
|
|
|
|
|
case 15:
|
|
|
|
|
sStr += "40"
|
|
|
|
|
case 16:
|
|
|
|
|
sStr += "40"
|
|
|
|
|
case 17:
|
|
|
|
|
sStr += "50"
|
|
|
|
|
case 18:
|
|
|
|
|
sStr += "50"
|
|
|
|
|
default:
|
2020-11-03 22:06:51 +01:00
|
|
|
sStr += "60"
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-06 16:22:38 +01:00
|
|
|
s.state.lastSReceivedAt = time.Now()
|
2020-11-03 22:06:51 +01:00
|
|
|
statusLog.reportS(sStr)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getS.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getS)
|
2020-11-04 10:18:32 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-04 10:41:12 +01:00
|
|
|
case 0x12:
|
|
|
|
|
if len(d) < 3 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getSWR.pending
|
2020-11-04 10:41:12 +01:00
|
|
|
}
|
2020-11-06 16:22:38 +01:00
|
|
|
s.state.lastSWRReceivedAt = time.Now()
|
2020-11-04 12:53:18 +01:00
|
|
|
statusLog.reportSWR(((float64(int(d[1])<<8)+float64(d[2]))/0x0120)*2 + 1)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getSWR.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getSWR)
|
2020-11-04 10:41:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-03 16:35:23 +01:00
|
|
|
case 0x15:
|
2020-11-04 10:18:32 +01:00
|
|
|
if len(d) < 3 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getVd.pending
|
2020-11-04 10:18:32 +01:00
|
|
|
}
|
2020-11-03 16:35:23 +01:00
|
|
|
statusLog.reportVd(((float64(int(d[1])<<8) + float64(d[2])) / 0x0241) * 16)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getVd.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getVd)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-03 16:35:23 +01:00
|
|
|
}
|
2020-11-04 10:18:32 +01:00
|
|
|
return true
|
2020-11-03 16:35:23 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
func (s *civControlStruct) decodePreampAGCNREnabled(d []byte) bool {
|
2020-11-03 16:19:37 +01:00
|
|
|
switch d[0] {
|
|
|
|
|
case 0x02:
|
2020-11-04 12:06:12 +01:00
|
|
|
if len(d) < 2 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getPreamp.pending && !s.state.setPreamp.pending
|
2020-11-04 12:06:12 +01:00
|
|
|
}
|
2020-11-03 16:19:37 +01:00
|
|
|
s.state.preamp = int(d[1])
|
|
|
|
|
statusLog.reportPreamp(s.state.preamp)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getPreamp.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getPreamp)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.setPreamp.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setPreamp)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-05 08:19:16 +01:00
|
|
|
case 0x12:
|
|
|
|
|
if len(d) < 2 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getAGC.pending && !s.state.setAGC.pending
|
2020-11-05 08:19:16 +01:00
|
|
|
}
|
|
|
|
|
s.state.agc = int(d[1])
|
|
|
|
|
var agc string
|
|
|
|
|
switch s.state.agc {
|
|
|
|
|
case 1:
|
|
|
|
|
agc = "F"
|
|
|
|
|
case 2:
|
|
|
|
|
agc = "M"
|
|
|
|
|
case 3:
|
|
|
|
|
agc = "S"
|
|
|
|
|
}
|
|
|
|
|
statusLog.reportAGC(agc)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getAGC.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getAGC)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.setAGC.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setAGC)
|
2020-11-05 08:19:16 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-04 10:01:07 +01:00
|
|
|
case 0x40:
|
2020-11-04 12:06:12 +01:00
|
|
|
if len(d) < 2 {
|
2020-11-09 09:40:18 +01:00
|
|
|
return !s.state.getNREnabled.pending && !s.state.setNREnabled.pending
|
2020-11-04 12:06:12 +01:00
|
|
|
}
|
2020-11-04 10:01:07 +01:00
|
|
|
if d[1] == 1 {
|
|
|
|
|
s.state.nrEnabled = true
|
|
|
|
|
} else {
|
|
|
|
|
s.state.nrEnabled = false
|
|
|
|
|
}
|
|
|
|
|
statusLog.reportNREnabled(s.state.nrEnabled)
|
2020-11-09 09:40:18 +01:00
|
|
|
if s.state.getNREnabled.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.getNREnabled)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if s.state.setNREnabled.pending {
|
|
|
|
|
s.removePendingCmd(&s.state.setNREnabled)
|
2020-11-04 12:06:12 +01:00
|
|
|
return false
|
|
|
|
|
}
|
2020-11-03 16:19:37 +01:00
|
|
|
}
|
2020-11-04 12:06:12 +01:00
|
|
|
return true
|
2020-11-03 16:19:37 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-09 09:40:18 +01:00
|
|
|
func (s *civControlStruct) initCmd(cmd *civCmd, name string, data []byte) {
|
|
|
|
|
*cmd = civCmd{}
|
|
|
|
|
cmd.name = name
|
|
|
|
|
cmd.cmd = data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) getPendingCmdIndex(cmd *civCmd) int {
|
|
|
|
|
for i := range s.state.pendingCmds {
|
|
|
|
|
if cmd == s.state.pendingCmds[i] {
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) removePendingCmd(cmd *civCmd) {
|
|
|
|
|
cmd.pending = false
|
|
|
|
|
index := s.getPendingCmdIndex(cmd)
|
|
|
|
|
if index < 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
s.state.pendingCmds[index] = s.state.pendingCmds[len(s.state.pendingCmds)-1]
|
|
|
|
|
s.state.pendingCmds[len(s.state.pendingCmds)-1] = nil
|
|
|
|
|
s.state.pendingCmds = s.state.pendingCmds[:len(s.state.pendingCmds)-1]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) sendCmd(cmd *civCmd) error {
|
|
|
|
|
cmd.pending = true
|
|
|
|
|
cmd.sentAt = time.Now()
|
|
|
|
|
if s.getPendingCmdIndex(cmd) < 0 {
|
|
|
|
|
s.state.pendingCmds = append(s.state.pendingCmds, cmd)
|
|
|
|
|
select {
|
|
|
|
|
case s.newPendingCmdAdded <- true:
|
|
|
|
|
default:
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return s.st.send(cmd.cmd)
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 23:06:34 +01:00
|
|
|
func (s *civControlStruct) setPwr(percent int) error {
|
|
|
|
|
v := uint16(0x0255 * (float64(percent) / 100))
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setPwr, "setPwr", []byte{254, 254, civAddress, 224, 0x14, 0x0a, byte(v >> 8), byte(v & 0xff), 253})
|
|
|
|
|
return s.sendCmd(&s.state.setPwr)
|
2020-10-30 23:06:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) incPwr() error {
|
|
|
|
|
if s.state.pwrPercent < 100 {
|
2020-10-30 23:58:10 +01:00
|
|
|
return s.setPwr(s.state.pwrPercent + 1)
|
2020-10-30 23:06:34 +01:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) decPwr() error {
|
|
|
|
|
if s.state.pwrPercent > 0 {
|
2020-10-30 23:58:10 +01:00
|
|
|
return s.setPwr(s.state.pwrPercent - 1)
|
2020-10-30 23:06:34 +01:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 09:41:36 +01:00
|
|
|
func (s *civControlStruct) setRFGain(percent int) error {
|
|
|
|
|
v := uint16(0x0255 * (float64(percent) / 100))
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setRFGain, "setRFGain", []byte{254, 254, civAddress, 224, 0x14, 0x02, byte(v >> 8), byte(v & 0xff), 253})
|
|
|
|
|
return s.sendCmd(&s.state.setRFGain)
|
2020-11-04 09:41:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) incRFGain() error {
|
|
|
|
|
if s.state.rfGainPercent < 100 {
|
|
|
|
|
return s.setRFGain(s.state.rfGainPercent + 1)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) decRFGain() error {
|
|
|
|
|
if s.state.rfGainPercent > 0 {
|
|
|
|
|
return s.setRFGain(s.state.rfGainPercent - 1)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 09:47:41 +01:00
|
|
|
func (s *civControlStruct) setSQL(percent int) error {
|
|
|
|
|
v := uint16(0x0255 * (float64(percent) / 100))
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setSQL, "setSQL", []byte{254, 254, civAddress, 224, 0x14, 0x03, byte(v >> 8), byte(v & 0xff), 253})
|
|
|
|
|
return s.sendCmd(&s.state.setSQL)
|
2020-11-04 09:47:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) incSQL() error {
|
|
|
|
|
if s.state.sqlPercent < 100 {
|
|
|
|
|
return s.setSQL(s.state.sqlPercent + 1)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) decSQL() error {
|
|
|
|
|
if s.state.sqlPercent > 0 {
|
|
|
|
|
return s.setSQL(s.state.sqlPercent - 1)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 10:01:07 +01:00
|
|
|
func (s *civControlStruct) setNR(percent int) error {
|
2020-11-05 10:43:13 +01:00
|
|
|
if !s.state.nrEnabled {
|
|
|
|
|
if err := s.toggleNR(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-04 10:01:07 +01:00
|
|
|
v := uint16(0x0255 * (float64(percent) / 100))
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setNR, "setNR", []byte{254, 254, civAddress, 224, 0x14, 0x06, byte(v >> 8), byte(v & 0xff), 253})
|
|
|
|
|
return s.sendCmd(&s.state.setNR)
|
2020-11-04 10:01:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) incNR() error {
|
|
|
|
|
if s.state.nrPercent < 100 {
|
|
|
|
|
return s.setNR(s.state.nrPercent + 1)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) decNR() error {
|
|
|
|
|
if s.state.nrPercent > 0 {
|
|
|
|
|
return s.setNR(s.state.nrPercent - 1)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 12:46:37 +01:00
|
|
|
func (s *civControlStruct) getDigit(v uint, n int) byte {
|
|
|
|
|
f := float64(v)
|
2020-10-30 23:58:10 +01:00
|
|
|
for n > 0 {
|
2020-11-01 12:46:37 +01:00
|
|
|
f /= 10
|
2020-10-30 23:58:10 +01:00
|
|
|
n--
|
|
|
|
|
}
|
2020-11-01 12:46:37 +01:00
|
|
|
return byte(uint(f) % 10)
|
2020-10-30 23:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 09:06:32 +01:00
|
|
|
func (s *civControlStruct) incFreq() error {
|
|
|
|
|
return s.setFreq(s.state.freq + s.state.ts)
|
2020-10-30 23:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 09:06:32 +01:00
|
|
|
func (s *civControlStruct) decFreq() error {
|
|
|
|
|
return s.setFreq(s.state.freq - s.state.ts)
|
2020-10-30 23:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-01 12:46:37 +01:00
|
|
|
func (s *civControlStruct) setFreq(f uint) error {
|
2020-10-30 23:58:10 +01:00
|
|
|
var b [5]byte
|
|
|
|
|
v0 := s.getDigit(f, 9)
|
|
|
|
|
v1 := s.getDigit(f, 8)
|
|
|
|
|
b[4] = v0<<4 | v1
|
|
|
|
|
v0 = s.getDigit(f, 7)
|
|
|
|
|
v1 = s.getDigit(f, 6)
|
|
|
|
|
b[3] = v0<<4 | v1
|
|
|
|
|
v0 = s.getDigit(f, 5)
|
|
|
|
|
v1 = s.getDigit(f, 4)
|
|
|
|
|
b[2] = v0<<4 | v1
|
|
|
|
|
v0 = s.getDigit(f, 3)
|
|
|
|
|
v1 = s.getDigit(f, 2)
|
|
|
|
|
b[1] = v0<<4 | v1
|
|
|
|
|
v0 = s.getDigit(f, 1)
|
|
|
|
|
v1 = s.getDigit(f, 0)
|
|
|
|
|
b[0] = v0<<4 | v1
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setFreq, "setFreq", []byte{254, 254, civAddress, 224, 5, b[0], b[1], b[2], b[3], b[4], 253})
|
|
|
|
|
return s.sendCmd(&s.state.setFreq)
|
2020-10-30 23:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-31 14:07:02 +01:00
|
|
|
func (s *civControlStruct) incOperatingMode() error {
|
|
|
|
|
s.state.operatingModeIdx++
|
|
|
|
|
if s.state.operatingModeIdx >= len(civOperatingModes) {
|
|
|
|
|
s.state.operatingModeIdx = 0
|
|
|
|
|
}
|
|
|
|
|
return civControl.setOperatingModeAndFilter(civOperatingModes[s.state.operatingModeIdx].code,
|
|
|
|
|
civFilters[s.state.filterIdx].code)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) decOperatingMode() error {
|
|
|
|
|
s.state.operatingModeIdx--
|
|
|
|
|
if s.state.operatingModeIdx < 0 {
|
|
|
|
|
s.state.operatingModeIdx = len(civOperatingModes) - 1
|
|
|
|
|
}
|
|
|
|
|
return civControl.setOperatingModeAndFilter(civOperatingModes[s.state.operatingModeIdx].code,
|
|
|
|
|
civFilters[s.state.filterIdx].code)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) incFilter() error {
|
|
|
|
|
s.state.filterIdx++
|
|
|
|
|
if s.state.filterIdx >= len(civFilters) {
|
|
|
|
|
s.state.filterIdx = 0
|
|
|
|
|
}
|
|
|
|
|
return civControl.setOperatingModeAndFilter(civOperatingModes[s.state.operatingModeIdx].code,
|
|
|
|
|
civFilters[s.state.filterIdx].code)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) decFilter() error {
|
|
|
|
|
s.state.filterIdx--
|
|
|
|
|
if s.state.filterIdx < 0 {
|
|
|
|
|
s.state.filterIdx = len(civFilters) - 1
|
|
|
|
|
}
|
|
|
|
|
return civControl.setOperatingModeAndFilter(civOperatingModes[s.state.operatingModeIdx].code,
|
|
|
|
|
civFilters[s.state.filterIdx].code)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) setOperatingModeAndFilter(modeCode, filterCode byte) error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setMode, "setMode", []byte{254, 254, civAddress, 224, 0x06, modeCode, filterCode, 253})
|
|
|
|
|
if err := s.sendCmd(&s.state.setMode); err != nil {
|
2020-10-31 14:07:02 +01:00
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return s.getMode()
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 22:12:30 +01:00
|
|
|
func (s *civControlStruct) setPTT(enable bool) error {
|
|
|
|
|
var b byte
|
|
|
|
|
if enable {
|
|
|
|
|
b = 1
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setPTT, "setPTT", []byte{254, 254, civAddress, 224, 0x1c, 0, b, 253})
|
|
|
|
|
return s.sendCmd(&s.state.setPTT)
|
2020-10-30 22:12:30 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-30 22:58:31 +01:00
|
|
|
func (s *civControlStruct) toggleTune() error {
|
|
|
|
|
if s.state.ptt {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var b byte
|
|
|
|
|
if !s.state.tune {
|
|
|
|
|
b = 2
|
|
|
|
|
} else {
|
|
|
|
|
b = 1
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setTune, "setTune", []byte{254, 254, civAddress, 224, 0x1c, 1, b, 253})
|
|
|
|
|
return s.sendCmd(&s.state.setTune)
|
2020-10-30 22:58:31 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-08 20:48:39 +01:00
|
|
|
func (s *civControlStruct) setDataMode(enable bool) error {
|
2020-10-31 14:07:02 +01:00
|
|
|
var b byte
|
|
|
|
|
var f byte
|
2020-11-08 20:48:39 +01:00
|
|
|
if enable {
|
2020-10-31 14:07:02 +01:00
|
|
|
b = 1
|
|
|
|
|
f = 1
|
|
|
|
|
} else {
|
|
|
|
|
b = 0
|
|
|
|
|
f = 0
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setDataMode, "setDataMode", []byte{254, 254, civAddress, 224, 0x1a, 0x06, b, f, 253})
|
|
|
|
|
return s.sendCmd(&s.state.setDataMode)
|
2020-10-31 14:07:02 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-08 20:48:39 +01:00
|
|
|
func (s *civControlStruct) toggleDataMode() error {
|
|
|
|
|
return s.setDataMode(!s.state.dataMode)
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-31 23:44:45 +01:00
|
|
|
func (s *civControlStruct) incBand() error {
|
|
|
|
|
s.state.bandChanging = true
|
|
|
|
|
i := s.state.bandIdx + 1
|
|
|
|
|
if i >= len(civBands) {
|
|
|
|
|
i = 0
|
|
|
|
|
}
|
|
|
|
|
f := civBands[i].freq
|
|
|
|
|
if f == 0 {
|
|
|
|
|
f = (civBands[i].freqFrom + civBands[i].freqTo) / 2
|
|
|
|
|
}
|
|
|
|
|
return s.setFreq(f)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) decBand() error {
|
|
|
|
|
s.state.bandChanging = true
|
|
|
|
|
i := s.state.bandIdx - 1
|
|
|
|
|
if i < 0 {
|
|
|
|
|
i = len(civBands) - 1
|
|
|
|
|
}
|
|
|
|
|
f := civBands[i].freq
|
|
|
|
|
if f == 0 {
|
|
|
|
|
f = civBands[i].freqFrom
|
|
|
|
|
}
|
|
|
|
|
return s.setFreq(f)
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-03 16:19:37 +01:00
|
|
|
func (s *civControlStruct) togglePreamp() error {
|
|
|
|
|
b := byte(s.state.preamp + 1)
|
|
|
|
|
if b > 2 {
|
|
|
|
|
b = 0
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setPreamp, "setPreamp", []byte{254, 254, civAddress, 224, 0x16, 0x02, b, 253})
|
|
|
|
|
return s.sendCmd(&s.state.setPreamp)
|
2020-11-03 16:19:37 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-05 08:19:16 +01:00
|
|
|
func (s *civControlStruct) toggleAGC() error {
|
|
|
|
|
b := byte(s.state.agc + 1)
|
|
|
|
|
if b > 3 {
|
|
|
|
|
b = 1
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setAGC, "setAGC", []byte{254, 254, civAddress, 224, 0x16, 0x12, b, 253})
|
|
|
|
|
return s.sendCmd(&s.state.setAGC)
|
2020-11-05 08:19:16 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 10:01:07 +01:00
|
|
|
func (s *civControlStruct) toggleNR() error {
|
|
|
|
|
var b byte
|
|
|
|
|
if !s.state.nrEnabled {
|
|
|
|
|
b = 1
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setNREnabled, "setNREnabled", []byte{254, 254, civAddress, 224, 0x16, 0x40, b, 253})
|
|
|
|
|
return s.sendCmd(&s.state.setNREnabled)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) setTS(b byte) error {
|
|
|
|
|
s.initCmd(&s.state.setTS, "setTS", []byte{254, 254, civAddress, 224, 0x10, b, 253})
|
|
|
|
|
return s.sendCmd(&s.state.setTS)
|
2020-11-04 10:01:07 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 09:06:32 +01:00
|
|
|
func (s *civControlStruct) incTS() error {
|
|
|
|
|
var b byte
|
|
|
|
|
if s.state.tsValue == 13 {
|
|
|
|
|
b = 0
|
|
|
|
|
} else {
|
|
|
|
|
b = s.state.tsValue + 1
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
return s.setTS(b)
|
2020-11-04 09:06:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) decTS() error {
|
|
|
|
|
var b byte
|
|
|
|
|
if s.state.tsValue == 0 {
|
|
|
|
|
b = 13
|
|
|
|
|
} else {
|
|
|
|
|
b = s.state.tsValue - 1
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
return s.setTS(b)
|
2020-11-04 09:06:32 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-08 20:48:39 +01:00
|
|
|
func (s *civControlStruct) setVFO(nr byte) error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setVFO, "setVFO", []byte{254, 254, civAddress, 224, 0x07, nr, 253})
|
|
|
|
|
return s.sendCmd(&s.state.setVFO)
|
2020-11-08 20:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-07 16:25:31 +01:00
|
|
|
func (s *civControlStruct) toggleVFO() error {
|
|
|
|
|
var b byte
|
|
|
|
|
if !s.state.vfoBActive {
|
|
|
|
|
b = 1
|
|
|
|
|
}
|
2020-11-08 20:48:39 +01:00
|
|
|
return s.setVFO(b)
|
2020-11-07 16:25:31 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-08 20:48:39 +01:00
|
|
|
func (s *civControlStruct) setSplit(mode splitMode) error {
|
2020-11-07 18:09:09 +01:00
|
|
|
var b byte
|
2020-11-08 20:48:39 +01:00
|
|
|
switch mode {
|
|
|
|
|
default:
|
|
|
|
|
b = 0x00
|
|
|
|
|
case splitModeOn:
|
|
|
|
|
b = 0x01
|
|
|
|
|
case splitModeDUPMinus:
|
|
|
|
|
b = 0x11
|
|
|
|
|
case splitModeDUPPlus:
|
|
|
|
|
b = 0x12
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.setSplit, "setSplit", []byte{254, 254, civAddress, 224, 0x0f, b, 253})
|
|
|
|
|
return s.sendCmd(&s.state.setSplit)
|
2020-11-08 20:48:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) toggleSplit() error {
|
|
|
|
|
var mode splitMode
|
2020-11-07 18:09:09 +01:00
|
|
|
switch s.state.splitMode {
|
|
|
|
|
case splitModeOff:
|
2020-11-08 20:48:39 +01:00
|
|
|
mode = splitModeOn
|
2020-11-07 18:09:09 +01:00
|
|
|
case splitModeOn:
|
2020-11-08 20:48:39 +01:00
|
|
|
mode = splitModeDUPMinus
|
2020-11-07 18:09:09 +01:00
|
|
|
case splitModeDUPMinus:
|
2020-11-08 20:48:39 +01:00
|
|
|
mode = splitModeDUPPlus
|
2020-11-07 18:09:09 +01:00
|
|
|
default:
|
2020-11-08 20:48:39 +01:00
|
|
|
mode = splitModeOff
|
2020-11-07 18:09:09 +01:00
|
|
|
}
|
2020-11-08 20:48:39 +01:00
|
|
|
return s.setSplit(mode)
|
2020-11-07 18:09:09 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-30 23:58:10 +01:00
|
|
|
func (s *civControlStruct) getFreq() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getFreq, "getFreq", []byte{254, 254, civAddress, 224, 3, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getFreq)
|
2020-10-30 23:58:10 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-31 14:07:02 +01:00
|
|
|
func (s *civControlStruct) getMode() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getMode, "getMode", []byte{254, 254, civAddress, 224, 4, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getMode)
|
2020-10-31 14:07:02 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-30 22:58:31 +01:00
|
|
|
func (s *civControlStruct) getDataMode() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getDataMode, "getDataMode", []byte{254, 254, civAddress, 224, 0x1a, 0x06, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getDataMode)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) getPwr() error {
|
|
|
|
|
s.initCmd(&s.state.getPwr, "getPwr", []byte{254, 254, civAddress, 224, 0x14, 0x0a, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getPwr)
|
2020-10-30 22:58:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) getTransmitStatus() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getTransmitStatus, "getTransmitStatus", []byte{254, 254, civAddress, 224, 0x1c, 0, 253})
|
|
|
|
|
if err := s.sendCmd(&s.state.getTransmitStatus); err != nil {
|
2020-10-30 22:58:31 +01:00
|
|
|
return err
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getTuneStatus, "getTuneStatus", []byte{254, 254, civAddress, 224, 0x1c, 1, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getTuneStatus)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) getPreamp() error {
|
|
|
|
|
s.initCmd(&s.state.getPreamp, "getPreamp", []byte{254, 254, civAddress, 224, 0x16, 0x02, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getPreamp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) getAGC() error {
|
|
|
|
|
s.initCmd(&s.state.getAGC, "getAGC", []byte{254, 254, civAddress, 224, 0x16, 0x12, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getAGC)
|
2020-10-30 22:58:31 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-03 16:35:23 +01:00
|
|
|
func (s *civControlStruct) getVd() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getVd, "getVd", []byte{254, 254, civAddress, 224, 0x15, 0x15, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getVd)
|
2020-11-03 16:35:23 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-03 20:55:27 +01:00
|
|
|
func (s *civControlStruct) getS() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getS, "getS", []byte{254, 254, civAddress, 224, 0x15, 0x02, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getS)
|
2020-11-03 20:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 09:18:48 +01:00
|
|
|
func (s *civControlStruct) getOVF() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getOVF, "getOVF", []byte{254, 254, civAddress, 224, 0x1a, 0x09, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getOVF)
|
2020-11-04 09:18:48 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 10:41:12 +01:00
|
|
|
func (s *civControlStruct) getSWR() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getSWR, "getSWR", []byte{254, 254, civAddress, 224, 0x15, 0x12, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getSWR)
|
2020-11-04 10:41:12 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 09:06:32 +01:00
|
|
|
func (s *civControlStruct) getTS() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getTS, "getTS", []byte{254, 254, civAddress, 224, 0x10, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getTS)
|
2020-11-04 09:06:32 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 09:41:36 +01:00
|
|
|
func (s *civControlStruct) getRFGain() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getRFGain, "getRFGain", []byte{254, 254, civAddress, 224, 0x14, 0x02, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getRFGain)
|
2020-11-04 09:41:36 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 09:47:41 +01:00
|
|
|
func (s *civControlStruct) getSQL() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getSQL, "getSQL", []byte{254, 254, civAddress, 224, 0x14, 0x03, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getSQL)
|
2020-11-04 09:47:41 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 10:01:07 +01:00
|
|
|
func (s *civControlStruct) getNR() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getNR, "getNR", []byte{254, 254, civAddress, 224, 0x14, 0x06, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getNR)
|
2020-11-04 10:01:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) getNREnabled() error {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.initCmd(&s.state.getNREnabled, "getNREnabled", []byte{254, 254, civAddress, 224, 0x16, 0x40, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getNREnabled)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *civControlStruct) getSplit() error {
|
|
|
|
|
s.initCmd(&s.state.getSplit, "getSplit", []byte{254, 254, civAddress, 224, 0x0f, 253})
|
|
|
|
|
return s.sendCmd(&s.state.getSplit)
|
2020-11-04 10:01:07 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-03 20:55:27 +01:00
|
|
|
func (s *civControlStruct) loop() {
|
|
|
|
|
for {
|
2020-11-09 09:40:18 +01:00
|
|
|
s.state.mutex.Lock()
|
|
|
|
|
nextPendingCmdTimeout := time.Hour
|
|
|
|
|
for i := range s.state.pendingCmds {
|
|
|
|
|
diff := time.Since(s.state.pendingCmds[i].sentAt)
|
|
|
|
|
if diff >= commandRetryTimeout {
|
|
|
|
|
nextPendingCmdTimeout = 0
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if diff < nextPendingCmdTimeout {
|
|
|
|
|
nextPendingCmdTimeout = diff
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s.state.mutex.Unlock()
|
|
|
|
|
|
2020-11-03 20:55:27 +01:00
|
|
|
select {
|
|
|
|
|
case <-s.deinitNeeded:
|
|
|
|
|
s.deinitFinished <- true
|
|
|
|
|
return
|
2020-11-09 09:40:18 +01:00
|
|
|
case <-time.After(statusPollInterval):
|
|
|
|
|
if !s.state.getS.pending && time.Since(s.state.lastSReceivedAt) >= statusPollInterval {
|
2020-11-06 16:22:38 +01:00
|
|
|
_ = s.getS()
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
if !s.state.getOVF.pending && time.Since(s.state.lastOVFReceivedAt) >= statusPollInterval {
|
2020-11-06 16:22:38 +01:00
|
|
|
_ = s.getOVF()
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
if !s.state.getSWR.pending && time.Since(s.state.lastSWRReceivedAt) >= statusPollInterval &&
|
|
|
|
|
(s.state.ptt || s.state.tune) {
|
2020-11-05 16:38:35 +01:00
|
|
|
_ = s.getSWR()
|
|
|
|
|
}
|
2020-11-03 20:55:27 +01:00
|
|
|
case <-s.resetSReadTimer:
|
2020-11-09 09:40:18 +01:00
|
|
|
case <-s.newPendingCmdAdded:
|
|
|
|
|
case <-time.After(nextPendingCmdTimeout):
|
|
|
|
|
s.state.mutex.Lock()
|
|
|
|
|
for _, cmd := range s.state.pendingCmds {
|
|
|
|
|
if time.Since(cmd.sentAt) >= commandRetryTimeout {
|
|
|
|
|
log.Debug("retrying cmd send ", cmd.name)
|
|
|
|
|
_ = s.sendCmd(cmd)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s.state.mutex.Unlock()
|
2020-11-03 20:55:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 22:12:30 +01:00
|
|
|
func (s *civControlStruct) init(st *serialStream) error {
|
|
|
|
|
s.st = st
|
|
|
|
|
|
2020-10-30 23:58:10 +01:00
|
|
|
if err := s.getFreq(); err != nil {
|
2020-10-29 09:39:13 +01:00
|
|
|
return err
|
|
|
|
|
}
|
2020-10-31 14:07:02 +01:00
|
|
|
if err := s.getMode(); err != nil {
|
2020-10-29 09:39:13 +01:00
|
|
|
return err
|
|
|
|
|
}
|
2020-10-30 22:58:31 +01:00
|
|
|
if err := s.getDataMode(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
if err := s.getPwr(); err != nil {
|
2020-10-30 14:55:25 +01:00
|
|
|
return err
|
|
|
|
|
}
|
2020-10-30 22:58:31 +01:00
|
|
|
if err := s.getTransmitStatus(); err != nil {
|
2020-10-29 09:39:13 +01:00
|
|
|
return err
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
if err := s.getPreamp(); err != nil {
|
2020-11-03 16:19:37 +01:00
|
|
|
return err
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
if err := s.getAGC(); err != nil {
|
2020-11-05 08:19:16 +01:00
|
|
|
return err
|
|
|
|
|
}
|
2020-11-03 16:35:23 +01:00
|
|
|
if err := s.getVd(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-11-03 20:55:27 +01:00
|
|
|
if err := s.getS(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-11-04 09:18:48 +01:00
|
|
|
if err := s.getOVF(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-11-04 10:41:12 +01:00
|
|
|
if err := s.getSWR(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-11-04 09:06:32 +01:00
|
|
|
if err := s.getTS(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-11-04 09:41:36 +01:00
|
|
|
if err := s.getRFGain(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-11-04 09:47:41 +01:00
|
|
|
if err := s.getSQL(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-11-04 10:01:07 +01:00
|
|
|
if err := s.getNR(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := s.getNREnabled(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-11-09 09:40:18 +01:00
|
|
|
if err := s.getSplit(); err != nil {
|
2020-11-07 18:09:09 +01:00
|
|
|
return err
|
|
|
|
|
}
|
2020-11-03 20:55:27 +01:00
|
|
|
|
|
|
|
|
s.deinitNeeded = make(chan bool)
|
|
|
|
|
s.deinitFinished = make(chan bool)
|
|
|
|
|
s.resetSReadTimer = make(chan bool)
|
2020-11-09 09:40:18 +01:00
|
|
|
s.newPendingCmdAdded = make(chan bool)
|
2020-11-03 20:55:27 +01:00
|
|
|
go s.loop()
|
2020-10-29 09:39:13 +01:00
|
|
|
return nil
|
|
|
|
|
}
|
2020-11-03 20:55:27 +01:00
|
|
|
|
|
|
|
|
func (s *civControlStruct) deinit() {
|
|
|
|
|
if s.deinitNeeded != nil {
|
|
|
|
|
s.deinitNeeded <- true
|
|
|
|
|
<-s.deinitFinished
|
|
|
|
|
}
|
|
|
|
|
s.deinitNeeded = nil
|
|
|
|
|
}
|