Fill in the macros from N1MM's function key page
Going down N1MM's published list, the ones a contest operator would miss:
| | |
|---|---|
| `{LASTEXCH}` | what the last station sent, built from the boxes the contest asks for |
| `{ROVERQTH}` | where a rover is now |
| `{TIME}`, `{DATE}`, `{TIMEGMT}`, `{DATEGMT}` | the clock and the calendar |
| `{ESC}`, `{CTRL-A}` to `{CTRL-Z}` | the control characters a TNC reads as commands |
| `{CTRLHOME}` | the cursor back in the callsign box |
| `{F1}` to `{F12}` | another of this radio's keys, where `{CTRLF1}` is the other radio's |
| `{CQ}` | makes any key a CQ key: it starts running and carries alternating CQ on |
| `{DIGQTCS}`, `{DIGQTCR}` | opens the WAE QTC window the way asked for |
| `{CLEARRIT}` | the receive offset back to zero, which is rigctld's `J 0` |
| `{FORCELOG}` | logs what is in the boxes, holes and all |
`{FORCELOG}` is the one that gives something up. `LogContact` refuses an entry
that is short or holds a value the contest will not take, so that a caller who
has not checked cannot log nonsense; `LogContactAnyway` is the way past it,
because a contact in the log with a hole in it can be filled in afterwards and
one that was never logged cannot. It still needs a callsign, and the status
line says the row will need fixing before the log goes in.
A key that names itself would send for ever, so a key sending another key
ignores the macro a second time down.
What is still passed over is written down in the README and unfinished.md.
Advanced voicing is the one that matters: N1MM says a callsign or a serial by
playing a recording per letter out of `LettersFiles`, which is why `!` and `#`
say nothing on phone here and why F5 is empty in N1MM's own SSB file too. The
three packet BBS date formats are passed over because there is nothing here to
check a guess at them against.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
This commit is contained in:
@@ -715,6 +715,7 @@ public sealed record StoredStation
|
||||
Name = Name,
|
||||
Power = Power,
|
||||
Club = Club,
|
||||
RoverQth = RoverQth,
|
||||
Check = Check,
|
||||
Precedence = Precedence,
|
||||
Latitude = Latitude,
|
||||
|
||||
@@ -80,6 +80,11 @@ public sealed partial class EntryWindow
|
||||
Refresh();
|
||||
}
|
||||
|
||||
/// True while a key is sending another key's message, so a message that
|
||||
/// names its own key — or two that name each other — stops there instead
|
||||
/// of going round for ever.
|
||||
private bool sendingAnotherKey;
|
||||
|
||||
private void SendMessage(int index) => _ = SendKeyAsync(index);
|
||||
|
||||
/// Sends one function key's message. The task finishes when the text has
|
||||
@@ -359,6 +364,45 @@ public sealed partial class EntryWindow
|
||||
_ = session.Digital?.ReturnToReceiveAsync();
|
||||
}
|
||||
break;
|
||||
case MessageCommand.CursorToCall:
|
||||
boxes[0].Focus();
|
||||
break;
|
||||
case MessageCommand.SendKey:
|
||||
if (!sendingAnotherKey
|
||||
&& int.TryParse(action.Argument, out int key)
|
||||
&& key is >= 1 and <= MessageFile.KeyCount)
|
||||
{
|
||||
sendingAnotherKey = true;
|
||||
try
|
||||
{
|
||||
SendMessage(key - 1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
sendingAnotherKey = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MessageCommand.CallCq:
|
||||
// what F1 does by itself: a CQ puts the station in run mode and
|
||||
// carries alternating CQ on to the other radio
|
||||
Logging.IsRunning = true;
|
||||
RememberCqFrequency();
|
||||
session.Alternating?.CarryOn();
|
||||
CqSent?.Invoke(this, EventArgs.Empty);
|
||||
break;
|
||||
case MessageCommand.SendQtc:
|
||||
_ = OpenQtcWindow(QtcDirection.Send);
|
||||
break;
|
||||
case MessageCommand.ReceiveQtc:
|
||||
_ = OpenQtcWindow(QtcDirection.Receive);
|
||||
break;
|
||||
case MessageCommand.ClearRit:
|
||||
_ = session.Radio?.ClearRitAsync();
|
||||
break;
|
||||
case MessageCommand.LogAnyway:
|
||||
LogContactAnyway();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -543,6 +543,30 @@ public sealed partial class EntryWindow : Window
|
||||
boxes[0].Focus();
|
||||
}
|
||||
|
||||
/// N1MM's `{FORCELOG}`: the contact goes in the log with whatever is in the
|
||||
/// boxes, holes and all. The status line says it was forced, because the
|
||||
/// row will need fixing before the log is sent in.
|
||||
private void LogContactAnyway()
|
||||
{
|
||||
if (Logging is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
Qso logged = Logging.LogContactAnyway();
|
||||
Status($"logged {logged.Call} as it stands — check it before sending the log in");
|
||||
}
|
||||
catch (Exception e) when (e is InvalidOperationException or IOException)
|
||||
{
|
||||
Status($"could not log the contact: {e.Message}");
|
||||
return;
|
||||
}
|
||||
ResetEsm();
|
||||
SyncBoxes();
|
||||
boxes[0].Focus();
|
||||
}
|
||||
|
||||
/// True when everything typed can go in the log. A value the contest will
|
||||
/// not take puts the reason in the status line and the cursor in its box,
|
||||
/// which is where the operator has to fix it.
|
||||
@@ -1136,7 +1160,11 @@ public sealed partial class EntryWindow : Window
|
||||
/// WAE QTC traffic, on Ctrl+Z as in N1MM. The contact is logged first if it
|
||||
/// is still in the boxes: the traffic belongs to a station that has been
|
||||
/// worked.
|
||||
private async Task OpenQtcWindow()
|
||||
///
|
||||
/// `wanted` is the way N1MM's `{DIGQTCS}` and `{DIGQTCR}` ask for, which
|
||||
/// is only allowed where the contest and the station leave it open. Ctrl+Z
|
||||
/// passes null and the rules decide.
|
||||
private async Task OpenQtcWindow(QtcDirection? wanted = null)
|
||||
{
|
||||
if (Logging is null)
|
||||
{
|
||||
@@ -1165,6 +1193,15 @@ public sealed partial class EntryWindow : Window
|
||||
Status(why);
|
||||
return;
|
||||
}
|
||||
if (wanted is { } asked)
|
||||
{
|
||||
if (direction is not QtcDirection.Either && direction != asked)
|
||||
{
|
||||
Status($"traffic with {station.Text} can only go the other way");
|
||||
return;
|
||||
}
|
||||
direction = asked;
|
||||
}
|
||||
if (direction is QtcDirection.Send && traffic.ToSend(station).Count == 0)
|
||||
{
|
||||
Status("nothing left to report to " + station.Text);
|
||||
|
||||
Reference in New Issue
Block a user