using Avalonia.Threading; using Nonemm.Core; using Nonemm.Network; using Nonemm.Session; using Nonemm.Spotting; namespace Nonemm.App; /// N1MM's local spot on a QSY: a callsign left in the entry window while the /// radio moves a long way on the same band is put on the bandmap where it was /// heard, and the boxes are wiped. The spot goes to the other stations on the /// network and to the programs listening for broadcast data. It is never sent /// to the cluster. public sealed partial class AppSession { private const int ShortestCallToSpot = 3; /// Raised after the boxes of a position were wiped here, so the window /// showing it can read them again. public event EventHandler? EntryWiped; private void TuneAndSpot(OperatingPosition position, Frequency frequency, Mode? mode, Frequency? transmit) { Frequency before = position.Frequency; position.Tune(frequency, mode, transmit); // the radio reports from its own thread, and the boxes belong to the // window's thread Dispatcher.UIThread.Post(() => SpotOnQsy(position, before)); } private void SpotOnQsy(OperatingPosition position, Frequency before) { string call = position.Entry.Call.Trim().ToUpperInvariant(); Frequency now = position.Frequency; Band? band = Bands.ForFrequency(before); if (call.Length < ShortestCallToSpot || call.All(char.IsAsciiDigit) || position.IsRunning || position.Editing is not null || position.IsEntryComplete || band is null || band != Bands.ForFrequency(now) || Math.Abs(now.Hertz - before.Hertz) <= Settings.QsySpotHertz || position.PendingQsy() is not null) { return; } Frequency tolerance = Frequency.FromHertz(Settings.TuningToleranceFor(position.Mode.Category)); if (Bandmap.Near(before, tolerance) is { IsStation: true } there && there.Call.Text.Equals(call, StringComparison.OrdinalIgnoreCase)) { return; } Spot spot = new( Callsign.Parse(call), before, DateTime.UtcNow, SpotSource.Operator, position.Me.Callsign, $"Local spot by {Settings.CurrentOperator}"); Bandmap.Add(spot); SendSpots([spot]); _ = link?.SendSpotAsync(new SharedSpot( call, spot.AtUtc, before, spot.Comment, Frequency.Zero, spot.Spotter, IsWorked: false)); position.Wipe(); EntryWiped?.Invoke(this, position); Reported?.Invoke(this, $"{call} spotted at {before.Kilohertz:0.0}"); } /// A spot another station on the network put on its bandmap. It is shown /// as it arrived, and is not passed on again. private void TakeSharedSpot(SharedSpot shared) { if (shared.Call.Length == 0 || shared.Frequency.Hertz <= 0) { return; } Bandmap.Add(new Spot( Callsign.Parse(shared.Call), shared.Frequency, shared.AtUtc == default ? DateTime.UtcNow : shared.AtUtc, SpotSource.Operator, shared.Spotter, shared.Comment) { Qsx = shared.Qsx, }); } }