mirror of
https://github.com/nonoo/kappanhang.git
synced 2025-12-06 08:02:00 +01:00
Add support for changing operating modes and filters with hotkeys
This commit is contained in:
parent
e72fc399ad
commit
65856b23e8
|
|
@ -166,6 +166,9 @@ not available.
|
||||||
- `;`, `'`: decrease, increase frequency 1kHz
|
- `;`, `'`: decrease, increase frequency 1kHz
|
||||||
- `{`, `}`: decrease, increase frequency 10kHz
|
- `{`, `}`: decrease, increase frequency 10kHz
|
||||||
- `[`, `]`: decrease, increase frequency 100kHz
|
- `[`, `]`: decrease, increase frequency 100kHz
|
||||||
|
- `n`, `m`: cycle through operating modes
|
||||||
|
- `d`, `f`: cycle through filters
|
||||||
|
- `D`: toggle data mode
|
||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
|
|
|
||||||
146
civcontrol.go
146
civcontrol.go
|
|
@ -7,6 +7,35 @@ import (
|
||||||
|
|
||||||
const civAddress = 0xa4
|
const civAddress = 0xa4
|
||||||
|
|
||||||
|
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},
|
||||||
|
}
|
||||||
|
|
||||||
type civControlStruct struct {
|
type civControlStruct struct {
|
||||||
st *serialStream
|
st *serialStream
|
||||||
|
|
||||||
|
|
@ -15,6 +44,9 @@ type civControlStruct struct {
|
||||||
ptt bool
|
ptt bool
|
||||||
tune bool
|
tune bool
|
||||||
pwrPercent int
|
pwrPercent int
|
||||||
|
operatingModeIdx int
|
||||||
|
filterIdx int
|
||||||
|
dataMode bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,16 +92,13 @@ func (s *civControlStruct) decodeFreq(d []byte) {
|
||||||
statusLog.reportFrequency(s.state.freq)
|
statusLog.reportFrequency(s.state.freq)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *civControlStruct) decodeFilterValue(v byte) string {
|
func (s *civControlStruct) decodeFilterValueToFilterIdx(v byte) int {
|
||||||
switch v {
|
for i := range civFilters {
|
||||||
case 0x01:
|
if civFilters[i].code == v {
|
||||||
return "FIL1"
|
return i
|
||||||
case 0x02:
|
|
||||||
return "FIL2"
|
|
||||||
case 0x03:
|
|
||||||
return "FIL3"
|
|
||||||
}
|
}
|
||||||
return ""
|
}
|
||||||
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *civControlStruct) decodeMode(d []byte) {
|
func (s *civControlStruct) decodeMode(d []byte) {
|
||||||
|
|
@ -78,32 +107,18 @@ func (s *civControlStruct) decodeMode(d []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var mode string
|
var mode string
|
||||||
switch d[0] {
|
for i := range civOperatingModes {
|
||||||
case 0x00:
|
if civOperatingModes[i].code == d[0] {
|
||||||
mode = "LSB"
|
s.state.operatingModeIdx = i
|
||||||
case 0x01:
|
mode = civOperatingModes[i].name
|
||||||
mode = "USB"
|
break
|
||||||
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
|
var filter string
|
||||||
if len(d) > 1 {
|
if len(d) > 1 {
|
||||||
filter = s.decodeFilterValue(d[1])
|
s.state.filterIdx = s.decodeFilterValueToFilterIdx(d[1])
|
||||||
|
filter = civFilters[s.state.filterIdx].name
|
||||||
}
|
}
|
||||||
statusLog.reportMode(mode, filter)
|
statusLog.reportMode(mode, filter)
|
||||||
|
|
||||||
|
|
@ -120,7 +135,11 @@ func (s *civControlStruct) decodeDataMode(d []byte) {
|
||||||
var filter string
|
var filter string
|
||||||
if d[1] == 1 {
|
if d[1] == 1 {
|
||||||
dataMode = "-D"
|
dataMode = "-D"
|
||||||
filter = s.decodeFilterValue(d[2])
|
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.reportDataMode(dataMode, filter)
|
||||||
|
|
@ -223,6 +242,49 @@ func (s *civControlStruct) setFreq(f float64) error {
|
||||||
return s.getFreq()
|
return s.getFreq()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if err := s.st.send([]byte{254, 254, civAddress, 224, 0x06, modeCode, filterCode, 253}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s.getMode()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *civControlStruct) setPTT(enable bool) error {
|
func (s *civControlStruct) setPTT(enable bool) error {
|
||||||
var b byte
|
var b byte
|
||||||
if enable {
|
if enable {
|
||||||
|
|
@ -245,10 +307,27 @@ func (s *civControlStruct) toggleTune() error {
|
||||||
return s.st.send([]byte{254, 254, civAddress, 224, 0x1c, 1, b, 253})
|
return s.st.send([]byte{254, 254, civAddress, 224, 0x1c, 1, b, 253})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *civControlStruct) toggleDataMode() error {
|
||||||
|
var b byte
|
||||||
|
var f byte
|
||||||
|
if !s.state.dataMode {
|
||||||
|
b = 1
|
||||||
|
f = 1
|
||||||
|
} else {
|
||||||
|
b = 0
|
||||||
|
f = 0
|
||||||
|
}
|
||||||
|
return s.st.send([]byte{254, 254, civAddress, 224, 0x1a, 0x06, b, f, 253})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *civControlStruct) getFreq() error {
|
func (s *civControlStruct) getFreq() error {
|
||||||
return s.st.send([]byte{254, 254, civAddress, 224, 3, 253})
|
return s.st.send([]byte{254, 254, civAddress, 224, 3, 253})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *civControlStruct) getMode() error {
|
||||||
|
return s.st.send([]byte{254, 254, civAddress, 224, 4, 253})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *civControlStruct) getDataMode() error {
|
func (s *civControlStruct) getDataMode() error {
|
||||||
return s.st.send([]byte{254, 254, civAddress, 224, 0x1a, 0x06, 253})
|
return s.st.send([]byte{254, 254, civAddress, 224, 0x1a, 0x06, 253})
|
||||||
}
|
}
|
||||||
|
|
@ -266,8 +345,7 @@ func (s *civControlStruct) init(st *serialStream) error {
|
||||||
if err := s.getFreq(); err != nil {
|
if err := s.getFreq(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Querying mode.
|
if err := s.getMode(); err != nil {
|
||||||
if err := s.st.send([]byte{254, 254, civAddress, 224, 4, 253}); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := s.getDataMode(); err != nil {
|
if err := s.getDataMode(); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -316,8 +316,6 @@ func (s *controlStream) init() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.common.pkt7.startPeriodicSend(&s.common, 2, false)
|
|
||||||
|
|
||||||
s.common.pkt0.init(&s.common)
|
s.common.pkt0.init(&s.common)
|
||||||
if err := s.sendPktLogin(); err != nil {
|
if err := s.sendPktLogin(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -344,6 +342,8 @@ func (s *controlStream) init() error {
|
||||||
return errors.New("invalid user/password")
|
return errors.New("invalid user/password")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.common.pkt7.startPeriodicSend(&s.common, 2, false)
|
||||||
|
|
||||||
copy(s.authID[:], r[26:32])
|
copy(s.authID[:], r[26:32])
|
||||||
s.gotAuthID = true
|
s.gotAuthID = true
|
||||||
if err := s.sendPktAuth(0x02); err != nil {
|
if err := s.sendPktAuth(0x02); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,36 @@ func (s *keyboardStruct) handleKey(k byte) {
|
||||||
log.Error("can't decrease freq: ", err)
|
log.Error("can't decrease freq: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 'm':
|
||||||
|
if civControl != nil {
|
||||||
|
if err := civControl.incOperatingMode(); err != nil {
|
||||||
|
log.Error("can't change mode: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'n':
|
||||||
|
if civControl != nil {
|
||||||
|
if err := civControl.decOperatingMode(); err != nil {
|
||||||
|
log.Error("can't change mode: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'f':
|
||||||
|
if civControl != nil {
|
||||||
|
if err := civControl.incFilter(); err != nil {
|
||||||
|
log.Error("can't change filter: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
if civControl != nil {
|
||||||
|
if err := civControl.decFilter(); err != nil {
|
||||||
|
log.Error("can't change filter: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'D':
|
||||||
|
if civControl != nil {
|
||||||
|
if err := civControl.toggleDataMode(); err != nil {
|
||||||
|
log.Error("can't change datamode: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue