using Nonemm.Contests; using Nonemm.Core; using Nonemm.Session; using Nonemm.Spotting; namespace Nonemm.App.Windows; /// The line above the callsign box. N1MM calls it the call frame: it says which /// spotted station the radio is sitting on, coloured the way the bandmap /// colours it, or that this is the frequency we are calling CQ on. Space with /// an empty callsign box takes the station out of the frame and into the box, /// which is how a station is worked without typing its call. public sealed partial class EntryWindow { /// Where we last called CQ, so the frame can say so when the radio comes /// back to it. private Frequency cqFrequency; /// What the frame holds, when it holds a callsign. `CQ-Frequency` is not /// one, and neither is nothing. private string framedCall = ""; /// How close counts as sitting on a spot, which is a different number for /// each mode: a phone signal is wide and a CW one is not. private Frequency TuningTolerance => Frequency.FromHertz(Math.Max( 0, session.Settings.TuningToleranceFor(Logging?.Mode.Category ?? ModeCategory.Cw))); private void ShowCallFrame() { framedCall = ""; if (Logging is null) { CallFrameText.Text = ""; return; } if (cqFrequency.Hertz > 0 && Math.Abs(Logging.Frequency.Hertz - cqFrequency.Hertz) <= TuningTolerance.Hertz) { CallFrameText.Text = "CQ-Frequency"; CallFrameText.Foreground = Verdicts.Cq; return; } if (session.Bandmap.Near(Logging.Frequency, TuningTolerance) is not { } spot) { CallFrameText.Text = ""; return; } // a mark saying the frequency is busy is shown but never taken into the // callsign box, because it is not a station framedCall = spot.IsStation ? spot.Call.Text : ""; CallFrameText.Text = spot.IsSplit ? $"{spot.Call.Text} — listening on {spot.Qsx.Kilohertz:0.0}" : spot.Call.Text; CallFrameText.Foreground = spot.IsStation ? Verdicts.Colour(VerdictFor(spot)) : Verdicts.Dupe; } private Verdict? VerdictFor(Spot spot) => Logging?.Log.Judge(new Qso { Id = "", TimestampUtc = DateTime.UtcNow, Call = spot.Call, Frequency = spot.Frequency, Mode = Logging.Mode, ContestName = Logging.Contest.Name, }); /// N1MM only takes the call out of the frame while searching: a running /// station is answering callers, not chasing the one it is sitting on. private bool TakeFramedCall() { if (Logging is null || Logging.IsRunning || framedCall.Length == 0 || Logging.Entry.Call.Trim().Length > 0) { return false; } Logging.Entry.Call = framedCall; return true; } /// The frequency a CQ went out on is the one the frame calls ours. private void RememberCqFrequency() { if (Logging is not null) { cqFrequency = Logging.Frequency; } } }