bug
This commit is contained in:
+30
-12
@@ -6,20 +6,38 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// debugLog writes CAT debug events to %APPDATA%/HamLog/cat.log so users can
|
||||
// diagnose mode/freq mismatches without rebuilding with -windowsconsole.
|
||||
//
|
||||
// Initialised lazily on first use. Falls back to the standard library
|
||||
// default logger (stderr, usually invisible in a Wails GUI build) if the
|
||||
// log file can't be opened.
|
||||
var debugLog = openDebugLog()
|
||||
// LogSink, when set by the host app at startup, receives every CAT debug
|
||||
// line so they land in the unified app log (opslog.log) alongside the rest
|
||||
// of OpsLog's diagnostics. Until it's wired we fall back to a dedicated
|
||||
// cat.log file so early-startup lines aren't lost.
|
||||
var LogSink func(format string, args ...any)
|
||||
|
||||
func openDebugLog() *log.Logger {
|
||||
// catLogger forwards Printf either to the host LogSink (preferred) or to a
|
||||
// local file/stderr fallback. Keeps the call sites (debugLog.Printf(...))
|
||||
// unchanged.
|
||||
type catLogger struct{ fallback *log.Logger }
|
||||
|
||||
func (c *catLogger) Printf(format string, args ...any) {
|
||||
if LogSink != nil {
|
||||
LogSink("cat: "+format, args...)
|
||||
return
|
||||
}
|
||||
if c.fallback != nil {
|
||||
c.fallback.Printf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// debugLog writes CAT debug events so users can diagnose mode/freq mismatches
|
||||
// without rebuilding with a console. Once LogSink is set, lines flow into the
|
||||
// main opslog.log.
|
||||
var debugLog = &catLogger{fallback: openFallbackLog()}
|
||||
|
||||
func openFallbackLog() *log.Logger {
|
||||
base, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return log.Default()
|
||||
}
|
||||
dir := filepath.Join(base, "HamLog")
|
||||
dir := filepath.Join(base, "OpsLog")
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return log.Default()
|
||||
}
|
||||
@@ -31,12 +49,12 @@ func openDebugLog() *log.Logger {
|
||||
return log.New(f, "", log.LstdFlags|log.Lmicroseconds)
|
||||
}
|
||||
|
||||
// DebugLogPath returns the path the cat.log file would be opened at, for
|
||||
// surfacing in the UI / docs.
|
||||
// DebugLogPath returns where the fallback cat.log lives, for surfacing in the
|
||||
// UI / docs. When LogSink is wired, CAT lines are in the main app log instead.
|
||||
func DebugLogPath() string {
|
||||
base, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return filepath.Join(base, "HamLog", "cat.log")
|
||||
return filepath.Join(base, "OpsLog", "cat.log")
|
||||
}
|
||||
|
||||
+80
-24
@@ -160,42 +160,98 @@ func (o *OmniRig) ReadState() (RigState, error) {
|
||||
|
||||
func (o *OmniRig) SetFrequency(hz int64) error {
|
||||
if o.rig == nil {
|
||||
debugLog.Printf("OmniRig.SetFrequency(%d): NOT CONNECTED", hz)
|
||||
return fmt.Errorf("not connected")
|
||||
}
|
||||
// OmniRig Freq is a Long (int32). Validate to avoid silent truncation.
|
||||
if hz < 0 || hz > 0x7fffffff {
|
||||
debugLog.Printf("OmniRig.SetFrequency(%d): out of int32 range", hz)
|
||||
return fmt.Errorf("frequency out of OmniRig int32 range")
|
||||
}
|
||||
hz32 := int32(hz)
|
||||
|
||||
// Pick the right OmniRig property. Many rig .ini files only define a
|
||||
// WRITE command for FreqA/FreqB but not the generic Freq — in which case
|
||||
// PutProperty(Freq) silently succeeds but the rig never moves. Write to
|
||||
// the active VFO's specific property when we know it; fall back to Freq.
|
||||
prop := "FreqA"
|
||||
if vfoVar, err := oleutil.GetProperty(o.rig, "Vfo"); err == nil {
|
||||
switch omniRigVfo(vfoVar.Val) {
|
||||
case "B", "BB", "BA":
|
||||
prop = "FreqB"
|
||||
case "A", "AA", "AB":
|
||||
prop = "FreqA"
|
||||
}
|
||||
// Log the rig's writable-params, status and VFO state up front so a
|
||||
// friend's session shows exactly what OmniRig reports for their rig.
|
||||
status, statusStr, rigType := int64(-1), "", ""
|
||||
if v, err := oleutil.GetProperty(o.rig, "Status"); err == nil {
|
||||
status = v.Val
|
||||
}
|
||||
debugLog.Printf("OmniRig.SetFrequency(%d Hz / %.6f MHz) → %s", hz, float64(hz)/1e6, prop)
|
||||
if _, err := oleutil.PutProperty(o.rig, prop, hz32); err != nil {
|
||||
debugLog.Printf("OmniRig.SetFrequency(%s) error: %v — falling back to Freq", prop, err)
|
||||
if _, err2 := oleutil.PutProperty(o.rig, "Freq", hz32); err2 != nil {
|
||||
debugLog.Printf("OmniRig.SetFrequency(Freq) also failed: %v", err2)
|
||||
return err2
|
||||
}
|
||||
if v, err := oleutil.GetProperty(o.rig, "StatusStr"); err == nil {
|
||||
statusStr = v.ToString()
|
||||
}
|
||||
if v, err := oleutil.GetProperty(o.rig, "RigType"); err == nil {
|
||||
rigType = v.ToString()
|
||||
}
|
||||
rawVfo, vfo := int64(-1), ""
|
||||
if vfoVar, err := oleutil.GetProperty(o.rig, "Vfo"); err == nil {
|
||||
rawVfo = vfoVar.Val
|
||||
vfo = omniRigVfo(vfoVar.Val)
|
||||
} else {
|
||||
debugLog.Printf("OmniRig.SetFrequency: Vfo read error: %v", err)
|
||||
}
|
||||
split := int64(0)
|
||||
if v, err := oleutil.GetProperty(o.rig, "Split"); err == nil {
|
||||
split = v.Val
|
||||
}
|
||||
// What can this rig's .ini actually write? OmniRig exposes a WriteableParams
|
||||
// bitmask — if FreqA/FreqB/Freq bits are missing, the write is a silent no-op.
|
||||
writeable := int64(-1)
|
||||
if v, err := oleutil.GetProperty(o.rig, "WriteableParams"); err == nil {
|
||||
writeable = v.Val
|
||||
}
|
||||
debugLog.Printf("OmniRig.SetFrequency(%d Hz / %.6f MHz): rig=%q status=%d(%s) vfo=%q(raw=%d) split=%d writeableParams=0x%X",
|
||||
hz, float64(hz)/1e6, rigType, status, statusStr, vfo, rawVfo, split, writeable)
|
||||
|
||||
// Pick the active VFO's specific property. Many rig .ini files only define
|
||||
// a WRITE command for FreqA/FreqB but not the generic Freq.
|
||||
prop := "FreqA"
|
||||
switch vfo {
|
||||
case "B", "BB", "BA":
|
||||
prop = "FreqB"
|
||||
case "A", "AA", "AB":
|
||||
prop = "FreqA"
|
||||
}
|
||||
|
||||
// Read back the active VFO freq after a short delay so the log shows
|
||||
// whether the rig actually moved. Useful when the .ini accepts the write
|
||||
// silently but the rig doesn't honour it (wrong WRITE command etc.).
|
||||
if fv, err := oleutil.GetProperty(o.rig, "Freq"); err == nil {
|
||||
debugLog.Printf("OmniRig.Freq immediately after Put = %d Hz", fv.Val)
|
||||
wroteOK := false
|
||||
if _, err := oleutil.PutProperty(o.rig, prop, hz32); err != nil {
|
||||
debugLog.Printf("OmniRig.SetFrequency: PutProperty(%s) error: %v", prop, err)
|
||||
} else {
|
||||
debugLog.Printf("OmniRig.SetFrequency: PutProperty(%s, %d) OK", prop, hz32)
|
||||
wroteOK = true
|
||||
}
|
||||
|
||||
// Belt-and-suspenders: when NOT in split, also write the generic Freq.
|
||||
// Icom .ini files commonly honour Freq (CI-V "set operating frequency")
|
||||
// but ignore FreqA/FreqB, so the rig changed mode but never moved — this
|
||||
// is exactly the IC-9100 "mode changes, freq doesn't" symptom.
|
||||
if split == 0 {
|
||||
if _, err := oleutil.PutProperty(o.rig, "Freq", hz32); err != nil {
|
||||
debugLog.Printf("OmniRig.SetFrequency: PutProperty(Freq) error: %v", err)
|
||||
if !wroteOK {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
debugLog.Printf("OmniRig.SetFrequency: PutProperty(Freq, %d) OK", hz32)
|
||||
}
|
||||
} else if !wroteOK {
|
||||
return fmt.Errorf("OmniRig: could not write %s and split is on (won't touch generic Freq)", prop)
|
||||
}
|
||||
|
||||
// Read back all three immediately. OmniRig is async (the CAT command is
|
||||
// queued + sent over serial), so these may still show the OLD value for
|
||||
// one poll cycle — but if they NEVER change in the next poll, the rig
|
||||
// isn't honouring the write (wrong .ini WRITE command for this model).
|
||||
fa, fb, fg := int64(-1), int64(-1), int64(-1)
|
||||
if v, err := oleutil.GetProperty(o.rig, "FreqA"); err == nil {
|
||||
fa = v.Val
|
||||
}
|
||||
if v, err := oleutil.GetProperty(o.rig, "FreqB"); err == nil {
|
||||
fb = v.Val
|
||||
}
|
||||
if v, err := oleutil.GetProperty(o.rig, "Freq"); err == nil {
|
||||
fg = v.Val
|
||||
}
|
||||
debugLog.Printf("OmniRig.SetFrequency: readback FreqA=%d FreqB=%d Freq=%d (target %d)", fa, fb, fg, hz)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user