fix(station): toggling tracking must not drop the antenna link
SetMotorFollow went through SaveUltrabeamSettings, which tears the client down and dials again. That is right when the transport changed and absurd for a checkbox: the operator flipped tracking and watched the antenna disconnect and come back, which on a remote controller is several seconds of a link that was working perfectly. The follow loop is a goroutine with its own stop channel and can be replaced on its own — the connection underneath never knows. Only the two keys this call actually changes are written, too: re-saving the whole block to change a checkbox means re-normalising host, port, baud and bands, and every one of those is a chance to alter something nobody asked to alter. startUltrabeam now starts the loop through the same function rather than its own copy. Two versions of "start the follow loop" drifting apart is how a step change quietly stops taking effect.
This commit is contained in:
@@ -14722,12 +14722,10 @@ func (a *App) startUltrabeam() {
|
||||
}
|
||||
a.motorAnt = c
|
||||
_ = a.motorAnt.Start()
|
||||
if s.Follow {
|
||||
stop := make(chan struct{})
|
||||
a.ubFollowStop = stop
|
||||
applog.Printf("ultrabeam: follow loop starting — covered bands %v, step %d kHz", s.Bands, s.StepKHz)
|
||||
go a.ultrabeamFollowLoop(a.motorAnt, s.StepKHz, s.Bands, stop)
|
||||
}
|
||||
// One place starts the follow loop, whether the antenna just connected or the
|
||||
// operator flipped tracking from the Station Control widget. Two copies of
|
||||
// this drifting apart is how a step change quietly stops taking effect.
|
||||
a.restartMotorFollow(s)
|
||||
if s.TXInhibit {
|
||||
stop := make(chan struct{})
|
||||
a.motorInhibStop = stop
|
||||
@@ -15122,9 +15120,45 @@ func (a *App) SetMotorFollow(on bool, stepKHz int) error {
|
||||
return fmt.Errorf("step must be 25, 50 or 100 kHz")
|
||||
}
|
||||
s.Follow = on
|
||||
// SaveUltrabeamSettings restarts the client, which is what actually starts or
|
||||
// stops the follow loop — the setting alone would not.
|
||||
return a.SaveUltrabeamSettings(s)
|
||||
|
||||
// Persist WITHOUT the restart. SaveUltrabeamSettings tears the client down and
|
||||
// dials again, which is right when the transport changed and absurd here: the
|
||||
// operator toggling tracking watched the antenna drop off and reconnect, and
|
||||
// on a remote controller that is several seconds of a link that was working.
|
||||
//
|
||||
// The follow loop is a goroutine with its own stop channel, so it can be
|
||||
// replaced on its own — the connection underneath never knows.
|
||||
// Only the two keys this call actually changes. Writing the whole block would
|
||||
// mean re-normalising host, port, baud and bands to change a checkbox, and
|
||||
// every one of those is a chance to alter something nobody asked to alter.
|
||||
if a.settings == nil {
|
||||
return fmt.Errorf("db not initialized")
|
||||
}
|
||||
if err := a.settings.Set(a.ctx, keyUltrabeamFollow, boolStr(s.Follow)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := a.settings.Set(a.ctx, keyUltrabeamStep, strconv.Itoa(s.StepKHz)); err != nil {
|
||||
return err
|
||||
}
|
||||
a.restartMotorFollow(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// restartMotorFollow swaps the follow loop for one matching the settings, leaving
|
||||
// the antenna connection alone.
|
||||
func (a *App) restartMotorFollow(s UltrabeamSettings) {
|
||||
if a.ubFollowStop != nil {
|
||||
close(a.ubFollowStop)
|
||||
a.ubFollowStop = nil
|
||||
}
|
||||
if !s.Follow || a.motorAnt == nil {
|
||||
applog.Printf("ultrabeam: follow loop stopped")
|
||||
return
|
||||
}
|
||||
stop := make(chan struct{})
|
||||
a.ubFollowStop = stop
|
||||
applog.Printf("ultrabeam: follow loop restarting — covered bands %v, step %d kHz", s.Bands, s.StepKHz)
|
||||
go a.ultrabeamFollowLoop(a.motorAnt, s.StepKHz, s.Bands, stop)
|
||||
}
|
||||
|
||||
// UltrabeamRetract retracts all elements (storage / safe position).
|
||||
|
||||
Reference in New Issue
Block a user