Carry alternating CQ on after a contact
Alternating CQ ran off every message the keyer finished, so working a station that answered started a CQ on the other radio, and Escape -- which stopped it outright -- was the way around that. It now follows N1MM: only the CQ message carries the alternation to the other radio, anything else holds it where it is, and so does Escape. The next CQ picks it up again, which is what the CQ after a logged contact does, so Ctrl+B is needed once rather than after every contact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
This commit is contained in:
@@ -84,6 +84,15 @@ public sealed partial class EntryWindow
|
||||
// the BARTG contest sends the time, and logs the one it sent
|
||||
Logging.StampSentTime();
|
||||
}
|
||||
// only a CQ carries alternating CQ on to the other radio
|
||||
if (index == Esm.CallCq)
|
||||
{
|
||||
session.Alternating?.CarryOn();
|
||||
}
|
||||
else
|
||||
{
|
||||
session.Alternating?.Hold();
|
||||
}
|
||||
string text = prefix + plan.Text;
|
||||
// the box has to point at this radio before the key does
|
||||
await session.PointTransmitAtAsync(radioNumber);
|
||||
|
||||
@@ -352,7 +352,9 @@ public sealed partial class EntryWindow : Window
|
||||
case Key.Escape:
|
||||
e.Handled = true;
|
||||
sending = false;
|
||||
session.Alternating?.Stop();
|
||||
// N1MM's Escape holds alternating CQ where it is rather than
|
||||
// switching it off; the next CQ carries it on
|
||||
session.Alternating?.Hold();
|
||||
_ = session.Keyer?.AbortAsync();
|
||||
Logging.Wipe();
|
||||
ResetEsm();
|
||||
@@ -618,7 +620,7 @@ public sealed partial class EntryWindow : Window
|
||||
private void OnStopSending(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
sending = false;
|
||||
session.Alternating?.Stop();
|
||||
session.Alternating?.Hold();
|
||||
_ = session.Keyer?.AbortAsync();
|
||||
Status("stopped sending");
|
||||
}
|
||||
|
||||
@@ -6,6 +6,13 @@ namespace Nonemm.Session;
|
||||
/// other radio and calls there. N1MM calls it dueling CQs and toggles it with
|
||||
/// Ctrl+B.
|
||||
///
|
||||
/// Only the CQ message carries the alternation on. A station answers, the
|
||||
/// operator sends their call and the exchange, and those messages leave the
|
||||
/// alternation where it is until the next CQ goes out. N1MM works the same
|
||||
/// way: it holds on any other message and on Escape, and carries on once the
|
||||
/// CQ message is sent again, which is what happens after the contact is
|
||||
/// logged.
|
||||
///
|
||||
/// It runs off the keyer's completion signal. Working out when a message ends
|
||||
/// from the length of the text would be a guess, and a guess that runs short
|
||||
/// keys the second radio while the first is still sending.
|
||||
@@ -18,6 +25,7 @@ public sealed class AlternatingCq : IDisposable
|
||||
private readonly Func<TimeSpan, CancellationToken, Task> wait;
|
||||
private readonly Lock gate = new();
|
||||
private CancellationTokenSource? running;
|
||||
private bool carriesOn = true;
|
||||
|
||||
/// `callCqOn` moves the operator to that radio and sends the CQ message.
|
||||
/// `wait` is there so a test does not have to sleep.
|
||||
@@ -52,6 +60,35 @@ public sealed class AlternatingCq : IDisposable
|
||||
/// The radio it is calling on now.
|
||||
public int RadioNumber { get; private set; }
|
||||
|
||||
/// True while a message finishing moves the CQ to the other radio, false
|
||||
/// while the operator is working a station.
|
||||
public bool CarriesOn
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
return carriesOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Says the CQ message has gone out, so the next message that finishes
|
||||
/// moves the CQ to the other radio.
|
||||
public void CarryOn() => Set(true);
|
||||
|
||||
/// Says something else has gone out, or that the operator has stopped the
|
||||
/// keyer, so the CQ stays where it is until the next one is sent.
|
||||
public void Hold() => Set(false);
|
||||
|
||||
private void Set(bool value)
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
carriesOn = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// Raised when it stops by itself, with the reason. Stopping by hand does
|
||||
/// not raise it.
|
||||
public event EventHandler<string>? Stopped;
|
||||
@@ -74,6 +111,7 @@ public sealed class AlternatingCq : IDisposable
|
||||
token = running.Token;
|
||||
}
|
||||
RadioNumber = radioNumber;
|
||||
Set(true);
|
||||
_ = CallAsync(radioNumber, token);
|
||||
}
|
||||
|
||||
@@ -98,7 +136,7 @@ public sealed class AlternatingCq : IDisposable
|
||||
CancellationToken token;
|
||||
lock (gate)
|
||||
{
|
||||
if (running is null)
|
||||
if (running is null || !carriesOn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user