diff --git a/src/Nonemm.App/AppSession.QsySpot.cs b/src/Nonemm.App/AppSession.QsySpot.cs index 6ccf3f4..7b0bac1 100644 --- a/src/Nonemm.App/AppSession.QsySpot.cs +++ b/src/Nonemm.App/AppSession.QsySpot.cs @@ -28,10 +28,32 @@ public sealed partial class AppSession Dispatcher.UIThread.Post(() => SpotOnQsy(position, before)); } - private void SpotOnQsy(OperatingPosition position, Frequency before) + /// Where the radio was when the call in each entry window was first seen. + /// A radio reports every few hundred hertz as the knob turns, so the move + /// is measured from here and not from the previous report. + private readonly Dictionary heardAt = []; + + private void SpotOnQsy(OperatingPosition position, Frequency reported) { string call = position.Entry.Call.Trim().ToUpperInvariant(); Frequency now = position.Frequency; + if (call.Length == 0) + { + heardAt.Remove(position); + return; + } + if (!heardAt.TryGetValue(position, out var anchor) || anchor.Call != call) + { + anchor = (call, reported); + heardAt[position] = anchor; + } + if (Bands.ForFrequency(anchor.At) != Bands.ForFrequency(now)) + { + // a band change starts again from the new band + heardAt[position] = (call, now); + return; + } + Frequency before = anchor.At; Band? band = Bands.ForFrequency(before); if (call.Length < ShortestCallToSpot || call.All(char.IsAsciiDigit) @@ -58,6 +80,7 @@ public sealed partial class AppSession SpotSource.Operator, position.Me.Callsign, $"Local spot by {Settings.CurrentOperator}"); + heardAt.Remove(position); Bandmap.Add(spot); SendSpots([spot]); _ = link?.SendSpotAsync(new SharedSpot( diff --git a/src/Nonemm.App/Windows/TelnetWindow.Filters.cs b/src/Nonemm.App/Windows/TelnetWindow.Filters.cs index 115ef3b..ecbbfc3 100644 --- a/src/Nonemm.App/Windows/TelnetWindow.Filters.cs +++ b/src/Nonemm.App/Windows/TelnetWindow.Filters.cs @@ -49,6 +49,7 @@ public sealed partial class TelnetWindow BlockedSpottersBox.Text = string.Join(' ', filter.BlockedSpotters); BlockedCallsBox.Text = string.Join(' ', filter.BlockedCalls); TimeoutBox.Text = session.Settings.SpotTimeoutMinutes.ToString(CultureInfo.InvariantCulture); + QsySpotBox.Text = session.Settings.QsySpotHertz.ToString(CultureInfo.InvariantCulture); SpotCommentBox.Text = session.Settings.SpotComment; } @@ -72,6 +73,7 @@ public sealed partial class TelnetWindow }, RandomizeSpots = RandomizeBox.IsChecked == true, SpotTimeoutMinutes = Minutes(TimeoutBox.Text, session.Settings.SpotTimeoutMinutes), + QsySpotHertz = Minutes(QsySpotBox.Text, session.Settings.QsySpotHertz), }); Show("*** filters applied — they hold for the spots that arrive from now on", NoticeColour); } diff --git a/src/Nonemm.App/Windows/TelnetWindow.axaml b/src/Nonemm.App/Windows/TelnetWindow.axaml index 14f56ac..4906e4f 100644 --- a/src/Nonemm.App/Windows/TelnetWindow.axaml +++ b/src/Nonemm.App/Windows/TelnetWindow.axaml @@ -122,6 +122,8 @@ + +