Mirror a radio from another computer's broadcast data
Listen for Radio broadcast data from another Nonemm or N1MM computer and record its frequency, mode and split as this computer's own radio. No radio is controlled. The settings are in the Configure Radios dialog. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
using System.Net.Sockets;
|
||||
using Avalonia.Threading;
|
||||
using Nonemm.Core;
|
||||
using Nonemm.Network;
|
||||
using Nonemm.Session;
|
||||
|
||||
namespace Nonemm.App;
|
||||
|
||||
/// Records the frequency, mode and split of a radio that another computer
|
||||
/// broadcasts as this station's own, for a station whose radio port is taken.
|
||||
/// Only the log's idea of the radio changes; no radio is commanded.
|
||||
/// Config > Configure Radios.
|
||||
public sealed partial class AppSession
|
||||
{
|
||||
private RadioMirror? mirror;
|
||||
|
||||
/// Starts, restarts or stops the listener, following what the settings now
|
||||
/// say. A port that cannot be opened is reported and the listener stays off.
|
||||
public void ApplyMirrorRadioSettings()
|
||||
{
|
||||
mirror?.Dispose();
|
||||
mirror = null;
|
||||
if (!Settings.MirrorRadioEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
mirror = new RadioMirror(Settings.MirrorRadioPort);
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
Reported?.Invoke(this, $"could not listen for radio data on port {Settings.MirrorRadioPort}: {e.Message}");
|
||||
return;
|
||||
}
|
||||
mirror.Failed += (_, problem) => Reported?.Invoke(this, problem);
|
||||
mirror.Received += (_, message) => Dispatcher.UIThread.Post(() => Mirror(message));
|
||||
}
|
||||
|
||||
/// Sets the target position to where the message says. This computer's own
|
||||
/// messages are skipped, because the radio data goes to this port too when
|
||||
/// the default address is used.
|
||||
private void Mirror(RadioBroadcast message)
|
||||
{
|
||||
RadioReport source = message.Radio;
|
||||
if (message.StationName == ComputerName
|
||||
|| source.RadioNumber != Settings.MirrorRadioSource
|
||||
|| (Settings.MirrorRadioStation.Length > 0
|
||||
&& !string.Equals(message.StationName, Settings.MirrorRadioStation, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
OperatingPosition? position = positions.FirstOrDefault(p => p.RadioNumber == Settings.MirrorRadioTarget);
|
||||
if (position is null || source.Frequency <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Frequency frequency = Frequency.FromHertz(source.Frequency);
|
||||
Frequency transmit = source.IsSplit ? Frequency.FromHertz(source.TransmitFrequency) : Frequency.Zero;
|
||||
Mode? mode = MirroredMode(source.Mode);
|
||||
|
||||
bool frequencyChanged = frequency != position.Frequency;
|
||||
bool modeChanged = mode is not null && mode != position.Mode;
|
||||
bool splitChanged = transmit != position.TransmitFrequency;
|
||||
if (!frequencyChanged && !modeChanged && !splitChanged)
|
||||
{
|
||||
return;
|
||||
}
|
||||
position.Tune(frequency, mode, transmit);
|
||||
}
|
||||
|
||||
/// N1MM names reverse CW and FSK differently from our modes. Null for a
|
||||
/// mode we have no name for, which leaves the mode where it is.
|
||||
private static Mode? MirroredMode(string name) => name.Trim().ToUpperInvariant() switch
|
||||
{
|
||||
"CW-R" or "CWR" => Modes.Cw,
|
||||
"FSK" or "RTTY-R" or "RTTYR" => Modes.Rtty,
|
||||
var other => Modes.Parse(other),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user