feat: Implemented UDP Outbound Adif message, freq to pstrotator
This commit is contained in:
@@ -551,6 +551,91 @@ func (b *IcomSerial) SetXITOn(on bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendCW keys a CW message through the rig's internal keyer (CI-V 0x17). The
|
||||
// text is upper-cased and filtered to keyer-legal characters; the radio must be
|
||||
// in CW mode. Messages longer than 30 characters are split across several 0x17
|
||||
// commands (the rig queues them).
|
||||
func (b *IcomSerial) SendCW(text string) error {
|
||||
msg := civ.FilterCW(text)
|
||||
if msg == "" {
|
||||
applog.Printf("icom cw: nothing to send (filtered %q → empty)", text)
|
||||
return nil
|
||||
}
|
||||
applog.Printf("icom cw: send %q (%d chars) to rig 0x%02X", msg, len(msg), b.rigAddr)
|
||||
for len(msg) > 0 {
|
||||
n := len(msg)
|
||||
if n > 30 {
|
||||
n = 30
|
||||
}
|
||||
chunk := msg[:n]
|
||||
msg = msg[n:]
|
||||
payload := append([]byte{civ.CmdSendCW}, []byte(chunk)...)
|
||||
if err := b.write(payload...); err != nil {
|
||||
applog.Printf("icom cw: write failed: %v", err)
|
||||
return err
|
||||
}
|
||||
// A missing ack is NOT fatal: some firmwares don't acknowledge 0x17, and
|
||||
// the message bytes were already written. Only an explicit NG (0xFA) means
|
||||
// the rig refused it (typically: not in CW mode / break-in off).
|
||||
f, err := b.recv(icomCmdTimeout, func(d civ.Decoded) bool { return d.Cmd == civ.OK || d.Cmd == civ.NG })
|
||||
if err != nil {
|
||||
applog.Printf("icom cw: chunk %q written, no ack (sent anyway): %v", chunk, err)
|
||||
} else if f.Cmd == civ.NG {
|
||||
applog.Printf("icom cw: rig REJECTED CW (0xFA) — put the rig in CW mode / enable break-in")
|
||||
return fmt.Errorf("icom: rig rejected CW — check CW mode / break-in")
|
||||
} else {
|
||||
applog.Printf("icom cw: chunk %q acked OK", chunk)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetBreakIn sets CW break-in (0=OFF, 1=SEMI, 2=FULL). Break-in must be on for
|
||||
// the 0x17 CW keyer to actually switch the rig to transmit.
|
||||
func (b *IcomSerial) SetBreakIn(mode int) error {
|
||||
if mode < 0 {
|
||||
mode = 0
|
||||
}
|
||||
if mode > 2 {
|
||||
mode = 2
|
||||
}
|
||||
applog.Printf("icom cw: set break-in %d", mode)
|
||||
if err := b.exec(civ.CmdSwitch, civ.SubSwBreakIn, byte(mode)); err != nil {
|
||||
applog.Printf("icom cw: set break-in failed: %v", err)
|
||||
return err
|
||||
}
|
||||
b.setCache(func(s *IcomTXState) { s.BreakIn = mode })
|
||||
return nil
|
||||
}
|
||||
|
||||
// StopCW aborts a CW message currently being sent (0x17 with the 0xFF stop code).
|
||||
func (b *IcomSerial) StopCW() error {
|
||||
applog.Printf("icom cw: stop")
|
||||
if err := b.write(civ.CmdSendCW, civ.StopCWByte); err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = b.recv(icomCmdTimeout, func(d civ.Decoded) bool { return d.Cmd == civ.OK || d.Cmd == civ.NG })
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetKeySpeed sets the CW keyer speed in WPM (CmdLevel 0x0C).
|
||||
func (b *IcomSerial) SetKeySpeed(wpm int) error {
|
||||
lvl := civ.WPMToKeyLevel(wpm)
|
||||
applog.Printf("icom cw: set key speed %d WPM (level %d)", wpm, lvl)
|
||||
if err := b.exec(append([]byte{civ.CmdLevel, civ.SubLevelKeySpeed}, civ.LevelToBCD(lvl)...)...); err != nil {
|
||||
applog.Printf("icom cw: set key speed failed: %v", err)
|
||||
return err
|
||||
}
|
||||
if wpm < civ.KeyMinWPM {
|
||||
wpm = civ.KeyMinWPM
|
||||
}
|
||||
if wpm > civ.KeyMaxWPM {
|
||||
wpm = civ.KeyMaxWPM
|
||||
}
|
||||
b.setCache(func(s *IcomTXState) { s.KeySpeedWPM = wpm })
|
||||
return nil
|
||||
}
|
||||
|
||||
// readRIT reads the offset + RIT/ΔTX on-off flags into st (best-effort).
|
||||
func (b *IcomSerial) readRIT(st *IcomTXState) {
|
||||
if err := b.write(civ.CmdRIT, civ.SubRITFreq); err == nil {
|
||||
@@ -812,6 +897,12 @@ func (b *IcomSerial) readDSP() {
|
||||
st.Filter = int(f)
|
||||
}
|
||||
b.readRIT(&st)
|
||||
if v, ok := b.readLevel(civ.SubLevelKeySpeed); ok {
|
||||
st.KeySpeedWPM = civ.KeyLevelToWPM(v)
|
||||
}
|
||||
if v, ok := b.readSwitch(civ.SubSwBreakIn); ok {
|
||||
st.BreakIn = int(v)
|
||||
}
|
||||
|
||||
b.dspMu.Lock()
|
||||
b.dsp = st
|
||||
|
||||
Reference in New Issue
Block a user