Add CW keying, function key messages and the documentation

The function keys send through cwdaemon or a WinKeyer, with N1MM's message
macros. Escape stops sending.

Settings are read with the reflection serializer rather than a generated one:
the generated one hands back null for every property the file leaves out
instead of the value the property is declared with, which crashed the program
the first time a new setting was added.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik
2026-08-27 11:23:30 +00:00
parent d96cbe146b
commit f5aa77ece3
25 changed files with 1002 additions and 26 deletions

View File

@@ -3,6 +3,7 @@ using Nonemm.Contests;
using Nonemm.Core;
using Nonemm.Core.Calls;
using Nonemm.Core.Country;
using Nonemm.Keying;
using Nonemm.Network;
using Nonemm.Rig;
using Nonemm.Session;
@@ -20,6 +21,7 @@ public sealed class AppSession : IDisposable
private RigctldRadio? radio;
private ClusterClient? cluster;
private StationNetwork? network;
private MessageSender? keyer;
public AppSession(UserPaths paths, Settings settings)
{
@@ -56,6 +58,8 @@ public sealed class AppSession : IDisposable
public StationNetwork? Network => network;
public MessageSender? Keyer => keyer;
public event EventHandler? Changed;
public event EventHandler? ContestChanged;
@@ -151,6 +155,31 @@ public sealed class AppSession : IDisposable
OpenContest(Logging.Instance.ContestNumber);
}
/// Starts, restarts or stops the keyer, following what the settings say.
/// A keyer that will not open is reported; the program keeps running
/// without one.
public void ApplyKeyerSettings()
{
keyer?.Dispose();
keyer = null;
switch (Settings.KeyerKind.ToLowerInvariant())
{
case "cwdaemon":
keyer = new CwDaemonSender(Settings.KeyerHost, Settings.KeyerPort);
break;
case "winkeyer":
WinkeyerSender winkeyer = new(Settings.KeyerSerialPort);
winkeyer.Open();
keyer = winkeyer;
break;
}
if (keyer is not null)
{
_ = keyer.SetSpeedAsync(Settings.KeyerSpeed);
}
Changed?.Invoke(this, EventArgs.Empty);
}
public void ConnectRadio()
{
radio?.Dispose();
@@ -204,6 +233,7 @@ public sealed class AppSession : IDisposable
radio?.Dispose();
cluster?.Dispose();
network?.Dispose();
keyer?.Dispose();
store?.Dispose();
}