Work QTC traffic on RTTY the way N1MM does
The QTC window put nothing on the air on RTTY except the lines themselves,
so the operator typed the rest into the digital window's transmit pane and
copied the lines by hand. N1MM sends a message for each step and fills the
lines in from a click. Both are here now, with N1MM's messages, N1MM's
defaults and N1MM's settings behind them.
The messages, all of them settings in the QTC window's setup area:
- RX Ready, `WAERXReadyText`, `{ENTERLF}I AM QRV BK`
- All Agn, `WAEAllAgnText`, `{ENTERLF}ALL AGN ALL AGN BK`
- Agn n, `WAEAGNText`, `{ENTERLF}AGN QTC: $ $ $ `, where `$` is the line
- Save, `WAESaveQTCText`, `{ENTERLF}R R R ALL OK BK`
- R U QRV, `WAERUQRVText`, `{ENTERLF}R U QRV BK`
- Save, reading traffic out, `WAESSaveQTCText`, `{ENTERLF}GL DE {MYCALL}`
Each keys the transmitter, sends the text and drops it again, and an empty
one sends nothing. The line spacing default is N1MM's `{ENTERLF}` rather
than `{ENTER}`, which was wrong.
The buttons: R U QRV and Snd Hdr were hidden while reading traffic out on
RTTY, though that is where N1MM starts — R U QRV is the first button
pressed. All Agn is new, and so is the S button on each line, which strikes
a line through a QTC that arrived too broken to read so the rows after it
keep their places; Agn n clears the strike and asks for that line again.
Clicking a line in the digital window fills the next row, which is how the
series is copied on RTTY: the other station sends the header and all ten
lines in one transmission. A click anywhere in a line hands the whole line
to the QTC window, which reads the time, the callsign and the serial number
out of it by shape and flashes the line to show it was taken. A line that is
not a QTC is left to mean what a click always means there.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Nonemm.Session;
|
||||
@@ -36,7 +37,29 @@ public static class QtcMessages
|
||||
/// What goes between the QTC lines on RTTY. N1MM keeps it as a macro rather
|
||||
/// than as characters, so an operator can put a carriage return there,
|
||||
/// which is what its default does.
|
||||
public const string DefaultRttySpacing = "{ENTER}";
|
||||
public const string DefaultRttySpacing = "{ENTERLF}";
|
||||
|
||||
/// The RTTY messages, with N1MM's defaults and the settings they come from
|
||||
/// in its own QTC setup window. Taking traffic down: `WAERXReadyText`,
|
||||
/// `WAEAllAgnText`, `WAEAGNText` and `WAESaveQTCText`. Reading it out:
|
||||
/// `WAERUQRVText` and `WAESSaveQTCText`.
|
||||
public const string DefaultRttyReady = "{ENTERLF}I AM QRV BK";
|
||||
|
||||
public const string DefaultRttyAllAgain = "{ENTERLF}ALL AGN ALL AGN BK";
|
||||
|
||||
/// `$` stands for the line asked for, so this goes out as
|
||||
/// `AGN QTC: 5 5 5`.
|
||||
public const string DefaultRttyLineAgain = "{ENTERLF}AGN QTC: $ $ $ ";
|
||||
|
||||
public const string DefaultRttySave = "{ENTERLF}R R R ALL OK BK";
|
||||
|
||||
public const string DefaultRttyAreYouReady = "{ENTERLF}R U QRV BK";
|
||||
|
||||
public const string DefaultRttySendSave = "{ENTERLF}GL DE {MYCALL}";
|
||||
|
||||
/// Asking for the header again. N1MM writes this into the program rather
|
||||
/// than into its settings on RTTY as well as on CW.
|
||||
public const string RttyHeaderAgain = "HDR AGN";
|
||||
|
||||
/// What stands in front of the series and what closes it. `{QTC}` stands
|
||||
/// for the header, so the default reads the series out twice for a station
|
||||
@@ -86,6 +109,18 @@ public static class QtcMessages
|
||||
public static string SendOne(string spacing, string line) =>
|
||||
$"{{TX}}{spacing}{line}{spacing}{{RX}}";
|
||||
|
||||
/// One of the short RTTY messages: it keys the transmitter, sends the text
|
||||
/// and drops it again, which is what N1MM wraps every one of them in. An
|
||||
/// empty message sends nothing at all.
|
||||
public static string Rtty(string message, string spacing = "") =>
|
||||
message.Trim().Length == 0 ? "" : $"{{TX}}{message}{spacing}{{RX}}";
|
||||
|
||||
/// The line-again message with the line number filled in. N1MM writes the
|
||||
/// number wherever the message has a `$`, so `AGN QTC: $ $ $` asks for
|
||||
/// line five as `AGN QTC: 5 5 5`.
|
||||
public static string LineAgain(string message, int line) =>
|
||||
message.Replace("$", line.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal);
|
||||
|
||||
public static string Spacing(string setting) =>
|
||||
setting.Replace("S", " ", StringComparison.Ordinal);
|
||||
|
||||
|
||||
@@ -235,6 +235,60 @@ public sealed class QtcTraffic
|
||||
: null;
|
||||
}
|
||||
|
||||
/// A line of received text read as the three fields of a QTC. On RTTY the
|
||||
/// other station sends the whole series in one transmission and the
|
||||
/// operator clicks the line rather than typing it, so what arrives here is
|
||||
/// a printed line with whatever the receiver made of the noise around it:
|
||||
/// `1435-DL1AAA-042`, or the same with spaces or slashes between.
|
||||
///
|
||||
/// The fields are taken by shape, in the order they are sent: the first
|
||||
/// group of digits is the time, the first thing shaped like a callsign is
|
||||
/// the callsign, and the last group of digits is the serial number. Null
|
||||
/// when the line does not hold all three.
|
||||
public static (string Time, string Call, string Number)? SplitLine(string text)
|
||||
{
|
||||
string[] parts = text.ToUpperInvariant()
|
||||
.Split(['-', '/', ' ', '\t', ',', '\\'], StringSplitOptions.RemoveEmptyEntries);
|
||||
string time = "";
|
||||
string call = "";
|
||||
string number = "";
|
||||
foreach (string part in parts)
|
||||
{
|
||||
string token = part.Trim();
|
||||
if (token.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (token.All(char.IsAsciiDigit))
|
||||
{
|
||||
if (time.Length == 0 && token.Length is 3 or 4)
|
||||
{
|
||||
time = token;
|
||||
}
|
||||
else if (call.Length > 0)
|
||||
{
|
||||
number = token;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (call.Length == 0 && time.Length > 0 && LooksLikeCall(token))
|
||||
{
|
||||
call = token;
|
||||
}
|
||||
}
|
||||
return time.Length > 0 && call.Length > 0 && number.Length > 0
|
||||
? (time, call, number)
|
||||
: null;
|
||||
}
|
||||
|
||||
/// Enough of a callsign to take off the air: letters and digits, at least
|
||||
/// one of each, three characters or more.
|
||||
private static bool LooksLikeCall(string token) =>
|
||||
token.Length is >= 3 and <= 12
|
||||
&& token.All(c => char.IsAsciiLetterOrDigit(c) || c == '/')
|
||||
&& token.Any(char.IsAsciiDigit)
|
||||
&& token.Any(char.IsAsciiLetter);
|
||||
|
||||
/// A time typed short is filled in from the line above, which is what N1MM
|
||||
/// does when the cursor leaves the box: `52` under `1148` reads as `1152`.
|
||||
/// As many characters are taken off the front of the line above as the
|
||||
|
||||
Reference in New Issue
Block a user