Add support for x and X rigctld commands

This commit is contained in:
Nonoo 2020-11-09 11:50:36 +01:00
parent 0d4dff6b08
commit 744a16a8aa
4 changed files with 201 additions and 75 deletions

View file

@ -95,8 +95,6 @@ type civControlStruct struct {
pendingCmds []*civCmd
getFreq civCmd
getMode civCmd
getDataMode civCmd
getPwr civCmd
getS civCmd
getOVF civCmd
@ -114,6 +112,8 @@ type civControlStruct struct {
getSplit civCmd
getMainVFOFreq civCmd
getSubVFOFreq civCmd
getMainVFOMode civCmd
getSubVFOMode civCmd
lastSReceivedAt time.Time
lastOVFReceivedAt time.Time
@ -126,6 +126,7 @@ type civControlStruct struct {
setFreq civCmd
setSubVFOFreq civCmd
setMode civCmd
setSubVFOMode civCmd
setPTT civCmd
setTune civCmd
setDataMode civCmd
@ -139,26 +140,28 @@ type civControlStruct struct {
pttTimeoutTimer *time.Timer
tuneTimeoutTimer *time.Timer
freq uint
subFreq uint
ptt bool
tune bool
pwrPercent int
rfGainPercent int
sqlPercent int
nrPercent int
nrEnabled bool
operatingModeIdx int
filterIdx int
dataMode bool
bandIdx int
bandChanging bool
preamp int
agc int
tsValue byte
ts uint
vfoBActive bool
splitMode splitMode
freq uint
subFreq uint
ptt bool
tune bool
pwrPercent int
rfGainPercent int
sqlPercent int
nrPercent int
nrEnabled bool
operatingModeIdx int
dataMode bool
filterIdx int
subOperatingModeIdx int
subDataMode bool
subFilterIdx int
bandIdx int
preamp int
agc int
tsValue byte
ts uint
vfoBActive bool
splitMode splitMode
}
}
@ -206,6 +209,8 @@ func (s *civControlStruct) decode(d []byte) bool {
return s.decodePreampAGCNREnabled(payload)
case 0x25:
return s.decodeVFOFreq(payload)
case 0x26:
return s.decodeVFOMode(payload)
}
return true
}
@ -257,34 +262,27 @@ func (s *civControlStruct) decodeFilterValueToFilterIdx(v byte) int {
return i
}
}
return -1
return 0
}
func (s *civControlStruct) decodeMode(d []byte) bool {
if len(d) < 1 {
return !s.state.getMode.pending && !s.state.setMode.pending
return !s.state.setMode.pending
}
var mode string
for i := range civOperatingModes {
if civOperatingModes[i].code == d[0] {
s.state.operatingModeIdx = i
mode = civOperatingModes[i].name
break
}
}
var filter string
if len(d) > 1 {
s.state.filterIdx = s.decodeFilterValueToFilterIdx(d[1])
filter = civFilters[s.state.filterIdx].name
}
statusLog.reportMode(mode, filter)
statusLog.reportMode(civOperatingModes[s.state.operatingModeIdx].name, s.state.dataMode,
civFilters[s.state.filterIdx].name)
if s.state.getMode.pending {
s.removePendingCmd(&s.state.getMode)
return false
}
if s.state.setMode.pending {
s.removePendingCmd(&s.state.setMode)
return false
@ -400,25 +398,18 @@ func (s *civControlStruct) decodeDataModeAndOVF(d []byte) bool {
switch d[0] {
case 0x06:
if len(d) < 3 {
return !s.state.getDataMode.pending && !s.state.setDataMode.pending
return !s.state.setDataMode.pending
}
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
}
statusLog.reportDataMode(dataMode, filter)
statusLog.reportMode(civOperatingModes[s.state.operatingModeIdx].name, s.state.dataMode,
civFilters[s.state.filterIdx].name)
if s.state.getDataMode.pending {
s.removePendingCmd(&s.state.getDataMode)
return false
}
if s.state.setDataMode.pending {
s.removePendingCmd(&s.state.setDataMode)
return false
@ -729,6 +720,60 @@ func (s *civControlStruct) decodeVFOFreq(d []byte) bool {
return true
}
func (s *civControlStruct) decodeVFOMode(d []byte) bool {
if len(d) < 2 {
return !s.state.getMainVFOMode.pending && !s.state.getSubVFOMode.pending && !s.state.setSubVFOMode.pending
}
operatingModeIdx := -1
for i := range civOperatingModes {
if civOperatingModes[i].code == d[1] {
operatingModeIdx = i
break
}
}
var dataMode bool
if len(d) > 2 && d[2] != 0 {
dataMode = true
}
filterIdx := -1
if len(d) > 3 {
filterIdx = s.decodeFilterValueToFilterIdx(d[3])
}
switch d[0] {
default:
s.state.operatingModeIdx = operatingModeIdx
s.state.dataMode = dataMode
if filterIdx >= 0 {
s.state.filterIdx = filterIdx
}
statusLog.reportMode(civOperatingModes[s.state.operatingModeIdx].name, s.state.dataMode,
civFilters[s.state.filterIdx].name)
if s.state.getMainVFOMode.pending {
s.removePendingCmd(&s.state.getMainVFOMode)
return false
}
case 0x01:
s.state.subOperatingModeIdx = operatingModeIdx
s.state.subDataMode = dataMode
s.state.subFilterIdx = filterIdx
statusLog.reportSubMode(civOperatingModes[s.state.subOperatingModeIdx].name, s.state.subDataMode,
civFilters[s.state.subFilterIdx].name)
if s.state.getSubVFOMode.pending {
s.removePendingCmd(&s.state.getSubVFOMode)
return false
}
if s.state.setSubVFOMode.pending {
s.removePendingCmd(&s.state.setSubVFOMode)
return false
}
}
return true
}
func (s *civControlStruct) initCmd(cmd *civCmd, name string, data []byte) {
*cmd = civCmd{}
cmd.name = name
@ -946,7 +991,12 @@ func (s *civControlStruct) setOperatingModeAndFilter(modeCode, filterCode byte)
if err := s.sendCmd(&s.state.setMode); err != nil {
return err
}
return s.getMode()
return s.getBothVFOMode()
}
func (s *civControlStruct) setSubVFOMode(modeCode, dataMode, filterCode byte) error {
s.initCmd(&s.state.setSubVFOMode, "setSubVFOMode", []byte{254, 254, civAddress, 224, 0x26, 0x01, modeCode, dataMode, filterCode, 253})
return s.sendCmd(&s.state.setSubVFOMode)
}
func (s *civControlStruct) setPTT(enable bool) error {
@ -1002,7 +1052,6 @@ func (s *civControlStruct) toggleDataMode() error {
}
func (s *civControlStruct) incBand() error {
s.state.bandChanging = true
i := s.state.bandIdx + 1
if i >= len(civBands) {
i = 0
@ -1015,7 +1064,6 @@ func (s *civControlStruct) incBand() error {
}
func (s *civControlStruct) decBand() error {
s.state.bandChanging = true
i := s.state.bandIdx - 1
if i < 0 {
i = len(civBands) - 1
@ -1081,7 +1129,10 @@ func (s *civControlStruct) decTS() error {
func (s *civControlStruct) setVFO(nr byte) error {
s.initCmd(&s.state.setVFO, "setVFO", []byte{254, 254, civAddress, 224, 0x07, nr, 253})
return s.sendCmd(&s.state.setVFO)
if err := s.sendCmd(&s.state.setVFO); err != nil {
return err
}
return s.getBothVFOMode()
}
func (s *civControlStruct) toggleVFO() error {
@ -1128,15 +1179,15 @@ func (s *civControlStruct) toggleSplit() error {
// return s.sendCmd(&s.state.getFreq)
// }
func (s *civControlStruct) getMode() error {
s.initCmd(&s.state.getMode, "getMode", []byte{254, 254, civAddress, 224, 4, 253})
return s.sendCmd(&s.state.getMode)
}
// func (s *civControlStruct) getMode() error {
// s.initCmd(&s.state.getMode, "getMode", []byte{254, 254, civAddress, 224, 4, 253})
// return s.sendCmd(&s.state.getMode)
// }
func (s *civControlStruct) getDataMode() error {
s.initCmd(&s.state.getDataMode, "getDataMode", []byte{254, 254, civAddress, 224, 0x1a, 0x06, 253})
return s.sendCmd(&s.state.getDataMode)
}
// func (s *civControlStruct) getDataMode() error {
// 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})
@ -1221,6 +1272,15 @@ func (s *civControlStruct) getBothVFOFreq() error {
return s.sendCmd(&s.state.getSubVFOFreq)
}
func (s *civControlStruct) getBothVFOMode() error {
s.initCmd(&s.state.getMainVFOMode, "getMainVFOMode", []byte{254, 254, civAddress, 224, 0x26, 0, 253})
if err := s.sendCmd(&s.state.getMainVFOMode); err != nil {
return err
}
s.initCmd(&s.state.getSubVFOMode, "getSubVFOMode", []byte{254, 254, civAddress, 224, 0x26, 1, 253})
return s.sendCmd(&s.state.getSubVFOMode)
}
func (s *civControlStruct) loop() {
for {
s.state.mutex.Lock()
@ -1273,10 +1333,7 @@ func (s *civControlStruct) init(st *serialStream) error {
if err := s.getBothVFOFreq(); err != nil {
return err
}
if err := s.getMode(); err != nil {
return err
}
if err := s.getDataMode(); err != nil {
if err := s.getBothVFOMode(); err != nil {
return err
}
if err := s.getPwr(); err != nil {
@ -1321,9 +1378,6 @@ func (s *civControlStruct) init(st *serialStream) error {
if err := s.getSplit(); err != nil {
return err
}
if err := s.getBothVFOFreq(); err != nil {
return err
}
s.deinitNeeded = make(chan bool)
s.deinitFinished = make(chan bool)
@ -1334,10 +1388,12 @@ func (s *civControlStruct) init(st *serialStream) error {
}
func (s *civControlStruct) deinit() {
if s.deinitNeeded != nil {
s.deinitNeeded <- true
<-s.deinitFinished
if s.deinitNeeded == nil {
return
}
s.deinitNeeded <- true
<-s.deinitFinished
s.deinitNeeded = nil
s.st = nil
}

View file

@ -288,6 +288,64 @@ func (s *rigctldStruct) processCmd(cmd string) (close bool, err error) {
return
}
err = s.sendReplyCode(rigctldNoError)
case cmd == "x":
civControl.state.mutex.Lock()
defer civControl.state.mutex.Unlock()
var mode string
if civControl.state.subDataMode {
mode = "PKT"
}
mode += civOperatingModes[civControl.state.subOperatingModeIdx].name
// This can be queried with a CIV command for accurate values by the way.
width := "3000"
switch civControl.state.subFilterIdx {
case 1:
width = "2400"
case 2:
width = "1800"
}
err = s.send(mode, "\n", width, "\n")
case cmdSplit[0] == "X":
mode := cmdSplit[1]
var dataMode byte
if mode[:3] == "PKT" {
dataMode = 1
mode = mode[3:]
}
var modeCode byte
var modeFound bool
for _, m := range civOperatingModes {
if m.name == mode {
modeCode = m.code
modeFound = true
break
}
}
if !modeFound {
err = fmt.Errorf("unknown mode %s", mode)
_ = s.sendReplyCode(rigctldInvalidParam)
return
}
var width int
width, err = strconv.Atoi(cmdSplit[2])
if err != nil {
_ = s.sendReplyCode(rigctldInvalidParam)
return
}
var filterCode byte
if width <= 1800 {
filterCode = 2
} else if width <= 2400 {
filterCode = 1
}
err = civControl.setSubVFOMode(modeCode, dataMode, filterCode)
if err != nil {
_ = s.sendReplyCode(rigctldInvalidParam)
} else {
_ = s.sendReplyCode(rigctldNoError)
}
case cmd == "v": // Ignore this command.
_ = s.sendReplyCode(rigctldUnsupportedCmd)
return

View file

@ -254,6 +254,7 @@ func (s *serialStream) init(devName string) error {
s.readFromSerialPort.frameTimeout = time.NewTimer(0)
<-s.readFromSerialPort.frameTimeout.C
civControl.deinit()
civControl = civControlStruct{}
if err := civControl.init(s); err != nil {
return err

View file

@ -22,6 +22,9 @@ type statusLogData struct {
mode string
dataMode string
filter string
subMode string
subDataMode string
subFilter string
preamp string
agc string
vd string
@ -137,7 +140,7 @@ func (s *statusLogStruct) reportSubFrequency(f uint) {
s.data.subFrequency = f
}
func (s *statusLogStruct) reportMode(mode, filter string) {
func (s *statusLogStruct) reportMode(mode string, dataMode bool, filter string) {
s.mutex.Lock()
defer s.mutex.Unlock()
@ -145,20 +148,28 @@ func (s *statusLogStruct) reportMode(mode, filter string) {
return
}
s.data.mode = mode
if dataMode {
s.data.dataMode = "-D"
} else {
s.data.dataMode = ""
}
s.data.filter = filter
}
func (s *statusLogStruct) reportDataMode(dataMode, filter string) {
func (s *statusLogStruct) reportSubMode(mode string, dataMode bool, filter string) {
s.mutex.Lock()
defer s.mutex.Unlock()
if s.data == nil {
return
}
s.data.dataMode = dataMode
if dataMode != "" {
s.data.filter = filter
s.data.subMode = mode
if dataMode {
s.data.subDataMode = "-D"
} else {
s.data.subDataMode = ""
}
s.data.subFilter = filter
}
func (s *statusLogStruct) reportPreamp(preamp int) {
@ -431,17 +442,17 @@ func (s *statusLogStruct) update() {
var splitStr string
if s.data.split != "" {
splitStr = " " + s.data.split
}
var subFreqStr string
if s.data.splitMode == splitModeOn {
subFreqStr = fmt.Sprintf("/%.6f", float64(s.data.subFrequency)/1000000)
if s.data.splitMode == splitModeOn {
splitStr += fmt.Sprintf("/%.6f/%s%s/%s", float64(s.data.subFrequency)/1000000,
s.data.subMode, s.data.subDataMode, s.data.subFilter)
}
}
var swrStr string
if (s.data.tune || s.data.ptt) && s.data.swr != "" {
swrStr = " SWR" + s.data.swr
}
s.data.line2 = fmt.Sprint(stateStr, " ", fmt.Sprintf("%.6f", float64(s.data.frequency)/1000000),
tsStr, modeStr, splitStr, subFreqStr, vdStr, txPowerStr, swrStr)
tsStr, modeStr, splitStr, vdStr, txPowerStr, swrStr)
up, down, lost, retransmits := netstat.get()
lostStr := "0"