Files
Nonemm/tools/Nonemm.EngineProbe/Program.cs
T
erikbrockoandClaude Sonnet 5.5 c18d79ba5a Run the digital bridge on Windows
The bridge launched its helper only through Wine. It now starts any
process, so on Windows it runs the helper directly. WineBridgeChannel is
renamed ProcessBridgeChannel.

WindowsControlSetup sets up the control side on Windows. The digital
dialog, AppSession, README and docs/digital-bridge.md describe the
Windows setup. publish-windows.sh builds a Windows release.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 21:56:47 +00:00

126 lines
4.4 KiB
C#

using Nonemm.Digital;
namespace Nonemm.EngineProbe;
/// Starts MMTTY through the bridge, asks it the questions in `EngineProbe`, and
/// writes what it answered to a file. It has to run where MMTTY runs: a sound
/// card and a Wine prefix with XMMT.ocx registered.
public static class Program
{
private const string Usage = """
usage: engine probe --engine <path to MMTTY.EXE> [options]
--engine <path> the engine to start, as a Linux path
--bridge <path> the bridge program (default bridge/nonemm-mmtty-bridge.exe)
--prefix <path> WINEPREFIX to run in (default: Wine's own)
--ptt <port> serial port to key (default: none, so no radio is keyed)
--out <file> where to write the report (default engine-probe.log)
--log <folder> where to write the protocol log, if it is wanted
The probe transmits: MMTTY makes tones on the sound card for about half a
minute. It keys no serial port unless --ptt says so, but a rig listening to
that sound card through VOX will still go on the air.
""";
public static async Task<int> Main(string[] arguments)
{
Dictionary<string, string> options;
try
{
options = Read(arguments);
}
catch (ArgumentException problem)
{
Console.Error.WriteLine(problem.Message);
Console.Error.WriteLine();
Console.Error.WriteLine(Usage);
return 1;
}
using CancellationTokenSource stopping = new();
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true;
stopping.Cancel();
};
using ProbeLog log = new(Option(options, "out", "engine-probe.log"));
MmttyEngine engine = new(
new ProcessBridgeChannel(
Option(options, "bridge", Path.Combine("bridge", "nonemm-mmtty-bridge.exe")),
options.GetValueOrDefault("prefix"),
logFolder: options.GetValueOrDefault("log")),
new MmttyOptions
{
EnginePath = options["engine"],
PttPort = Option(options, "ptt", ""),
});
try
{
log.Write($"starting {options["engine"]}");
await engine.StartAsync(stopping.Token).ConfigureAwait(false);
log.Write($"MMTTY {engine.Version} is up");
await new EngineProbe(engine, log).RunAsync(stopping.Token).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
log.Write("stopped");
}
catch (Exception problem)
{
log.Write($"failed: {problem.Message}");
Console.Error.WriteLine(problem);
return 1;
}
finally
{
await Shutdown(engine, log).ConfigureAwait(false);
Console.WriteLine();
Console.WriteLine($"the report is in {log.Path}");
}
return 0;
}
/// The engine is left keyed if the probe stopped partway through, so the
/// transmission is aborted before the engine is shut down, whatever
/// happened.
private static async Task Shutdown(MmttyEngine engine, ProbeLog log)
{
try
{
await engine.AbortAsync().ConfigureAwait(false);
await engine.StopAsync().ConfigureAwait(false);
}
catch (Exception problem)
{
log.Write($"the engine did not shut down cleanly: {problem.Message}");
}
engine.Dispose();
}
private static Dictionary<string, string> Read(string[] arguments)
{
Dictionary<string, string> options = [];
for (int i = 0; i < arguments.Length; i += 2)
{
if (!arguments[i].StartsWith("--", StringComparison.Ordinal))
{
throw new ArgumentException($"expected an option, found {arguments[i]}");
}
if (i + 1 >= arguments.Length)
{
throw new ArgumentException($"{arguments[i]} needs a value");
}
options[arguments[i][2..]] = arguments[i + 1];
}
if (!options.ContainsKey("engine"))
{
throw new ArgumentException("--engine is required");
}
return options;
}
private static string Option(Dictionary<string, string> options, string name, string fallback) =>
options.TryGetValue(name, out string? given) ? given : fallback;
}