feat(steppir): a Calibrate button, and Retract explains itself
Calibrate was in the protocol notes at the top of the package ('V') and nowhere
else. It drives every element to its end stop so the controller re-learns where
zero is, and it is the cure for the one SteppIR fault an operator cannot reason
about: an antenna that tunes to the wrong length. The controller counts steps
from a remembered position, so once that memory is wrong — a power cut in
mid-move, elements pushed by hand, a motor that slipped — every frequency after
it is wrong by the same amount, silently.
It asks before it runs. Minutes, every element travelling its full length, and
the antenna unusable until it finishes: right answer to a mistuned beam, wrong
answer to a stray click during a contest.
It sits beside Retract as a two-column row rather than a second full-width
button. The docked widget is narrow and already tall, and the pair reads as what
it is — the two commands that move every element at once.
Retract (Home) was already there and worked on a SteppIR; it now carries a
tooltip saying what it is for, because "retract elements" does not tell an
operator that this is the storage position and that the next tune brings them
back out unaided.
An Ultrabeam controller has no calibration command, and the adapter says so
instead of pretending — the antenna interface is shared, and a button that
silently does nothing is worse than one that explains itself.
Untested on hardware: the byte is from SteppIR's own Transceiver Interface note,
which is the same source the rest of this package was cross-checked against.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
@@ -18212,6 +18212,10 @@ type motorAntenna interface {
|
||||
SetFrequency(khz, dir int) error
|
||||
SetDirection(dir int) error
|
||||
Retract() error
|
||||
// Calibrate re-learns where the elements are by driving them to their end
|
||||
// stops. SteppIR only: an Ultrabeam has no such command, and says so rather
|
||||
// than pretending.
|
||||
Calibrate() error
|
||||
LastSetKHz() int
|
||||
Status() motorStatus
|
||||
// Elements returns the per-element lengths (mm) when the antenna exposes them
|
||||
@@ -18239,11 +18243,14 @@ type ubAdapter struct {
|
||||
freqMin, freqMax int
|
||||
}
|
||||
|
||||
func (a ubAdapter) Start() error { return a.c.Start() }
|
||||
func (a ubAdapter) Stop() { a.c.Stop() }
|
||||
func (a ubAdapter) SetFrequency(k, d int) error { return a.c.SetFrequency(k, d) }
|
||||
func (a ubAdapter) SetDirection(d int) error { return a.c.SetDirection(d) }
|
||||
func (a ubAdapter) Retract() error { return a.c.Retract() }
|
||||
func (a ubAdapter) Start() error { return a.c.Start() }
|
||||
func (a ubAdapter) Stop() { a.c.Stop() }
|
||||
func (a ubAdapter) SetFrequency(k, d int) error { return a.c.SetFrequency(k, d) }
|
||||
func (a ubAdapter) SetDirection(d int) error { return a.c.SetDirection(d) }
|
||||
func (a ubAdapter) Retract() error { return a.c.Retract() }
|
||||
func (a ubAdapter) Calibrate() error {
|
||||
return fmt.Errorf("calibration is a SteppIR command — an Ultrabeam controller has none")
|
||||
}
|
||||
func (a ubAdapter) LastSetKHz() int { return a.c.LastSetKHz() }
|
||||
func (a ubAdapter) SetElement(n, mm int) error { return a.c.ModifyElement(n, mm) }
|
||||
func (a ubAdapter) ReadElements() ([]int, error) { return a.c.ReadElements() }
|
||||
@@ -18282,6 +18289,7 @@ func (a steppirAdapter) Stop() { a.c.Stop() }
|
||||
func (a steppirAdapter) SetFrequency(k, d int) error { return a.c.SetFrequency(k, d) }
|
||||
func (a steppirAdapter) SetDirection(d int) error { return a.c.SetDirection(d) }
|
||||
func (a steppirAdapter) Retract() error { return a.c.Retract() }
|
||||
func (a steppirAdapter) Calibrate() error { return a.c.Calibrate() }
|
||||
func (a steppirAdapter) LastSetKHz() int { return a.c.LastSetKHz() }
|
||||
func (a steppirAdapter) Elements() []int { return nil } // SteppIR: no per-element control
|
||||
func (a steppirAdapter) SetElement(_, _ int) error {
|
||||
@@ -19198,6 +19206,24 @@ func (a *App) restartMotorFollow(s UltrabeamSettings) {
|
||||
go a.ultrabeamFollowLoop(a.motorAnt, s.TrackMode, s.StepKHz, s.Bands, stop)
|
||||
}
|
||||
|
||||
// MotorCalibrate runs a SteppIR calibration: the elements go to their end stops
|
||||
// so the controller re-learns where zero is.
|
||||
//
|
||||
// The cure for an antenna that tunes to the wrong length — after a power cut
|
||||
// mid-move, after the elements were pushed by hand, after a motor slipped. The
|
||||
// controller counts steps from a remembered position, and once that memory is
|
||||
// wrong, every frequency after it is wrong by the same amount.
|
||||
//
|
||||
// Minutes, and every element travels its full length. Not a contest-time button,
|
||||
// which is why the interface asks first.
|
||||
func (a *App) MotorCalibrate() error {
|
||||
if a.motorAnt == nil {
|
||||
return fmt.Errorf("antenna not connected")
|
||||
}
|
||||
applog.Printf("antenna: calibration started — the elements go to their end stops, this takes minutes")
|
||||
return a.motorAnt.Calibrate()
|
||||
}
|
||||
|
||||
// UltrabeamRetract retracts all elements (storage / safe position).
|
||||
func (a *App) UltrabeamRetract() error {
|
||||
if a.motorAnt == nil {
|
||||
|
||||
Reference in New Issue
Block a user