Skip to content

Commit

Permalink
Websockets & RF Scanning:
Browse files Browse the repository at this point in the history
 - Added support for RF scanning
 - Added channel name sanitisation
 - Fixed a few small bugs
 - Added API methods for RF scanning
 - setWirelessMicReceiver parameter names are now case insensitive
 - Added WebSocket API
 - Added property change notifications and metering to WebSocket API
 - Refactoring
  • Loading branch information
space928 committed Jun 27, 2024
1 parent 40df367 commit ff20f7b
Show file tree
Hide file tree
Showing 10 changed files with 683 additions and 43 deletions.
76 changes: 72 additions & 4 deletions WirelessMicSuiteServer/IWirelessMicReceiver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public interface IWirelessMicReceiver : IDisposable, INotifyPropertyChanged
/// <summary>
/// The MAC address of the wireless receiver.
/// </summary>
public abstract MACAddress? MACAddres { get; }
public abstract MACAddress? MACAddress { get; }
}

public interface IWirelessMic : INotifyPropertyChanged
Expand All @@ -102,6 +102,7 @@ public interface IWirelessMic : INotifyPropertyChanged
/// </summary>
public abstract ConcurrentQueue<MeteringData>? MeterData { get; }
public abstract MeteringData? LastMeterData { get; }
public abstract RFScanData RFScanData { get; }

/// <summary>
/// A unique identifier for this wireless transmitter. Note that this is associated with the
Expand Down Expand Up @@ -149,6 +150,14 @@ public interface IWirelessMic : INotifyPropertyChanged
//public void Unsubscribe();
public void StartMetering(int periodMS);
public void StopMetering();

/// <summary>
/// Starts scanning the RF spectrum using this receiver. Audio is muted while this task is executing.
/// </summary>
/// <param name="range">The frequency range to scan, must be within the frequency range supported by the receiver.</param>
/// <param name="stepSize">If supported, the step size in Hz between each RF sample.</param>
/// <returns>A data structure containing the results of the scan.</returns>
public Task<RFScanData> StartRFScan(FrequencyRange range, ulong stepSize);
}

/// <summary>
Expand Down Expand Up @@ -190,7 +199,7 @@ public struct WirelessReceiverData(IWirelessMicReceiver other) : IWirelessMicRec
public IPv4Address? Subnet { get; set; } = other.Subnet;
public IPv4Address? Gateway { get; set; } = other.Gateway;
public IPMode? IPMode { get; set; } = other.IPMode;
public MACAddress? MACAddres { get; init; } = other.MACAddres;
public MACAddress? MACAddress { get; init; } = other.MACAddress;

public event PropertyChangedEventHandler? PropertyChanged;

Expand All @@ -205,6 +214,7 @@ public struct WirelessMicData(IWirelessMic other) : IWirelessMic
{
[JsonIgnore] public IWirelessMicReceiver Receiver { get; init; } = other.Receiver;
[JsonIgnore] public ConcurrentQueue<MeteringData>? MeterData { get; init; } = other.MeterData;
[JsonIgnore] public RFScanData RFScanData { get; init; } = other.RFScanData;
[JsonInclude] public MeteringData? LastMeterData { get; init; } = other.LastMeterData;

[JsonInclude] public readonly uint ReceiverID => Receiver.UID;
Expand All @@ -226,12 +236,70 @@ public void StartMetering(int periodMS)
throw new NotImplementedException();
}

public Task<RFScanData> StartRFScan(FrequencyRange range, ulong stepSize)
{
throw new NotImplementedException();
}

public void StopMetering()
{
throw new NotImplementedException();
}
}

/// <summary>
/// The data resulting from an RF spectrum scan.
/// </summary>
public struct RFScanData
{
/// <summary>
/// The recorded RF level samples at each sampled frequency.
/// </summary>
public List<Sample> Samples { get; internal set; }
/// <summary>
/// The frequency range covered by the scan.
/// </summary>
public FrequencyRange FrequencyRange { get; internal set; }
/// <summary>
/// The distance between RF samples in Hz.
/// </summary>
public ulong StepSize { get; internal set; }
/// <summary>
/// The percentage completion of the RF scan operation.
/// </summary>
public float Progress { get; internal set; }
/// <summary>
/// The current state of the RF scan operation.
/// </summary>
public Status State { get; internal set; }

/// <summary>
/// An RF spectrum sample.
/// </summary>
/// <param name="freq">The frequency of the sample in Hz.</param>
/// <param name="strength">The strength of the sample in dBm.</param>
public readonly struct Sample(ulong freq, float strength)
{
/// <summary>
/// The frequency of the sample in Hz.
/// </summary>
public readonly ulong Frequency { get; init; } = freq;
/// <summary>
/// The strength of the sample in dBm.
/// </summary>
public readonly float Strength { get; init; } = strength;
}

[JsonConverter(typeof(JsonStringEnumConverter<Status>))]
public enum Status
{
Started,
Running,
Completed,
Failure
}
}

/// <summary>
/// A frequency range in Hz.
/// </summary>
Expand All @@ -242,11 +310,11 @@ public struct FrequencyRange(ulong startFreq, ulong endFreq)
/// <summary>
/// The lower bound of the tunable frequency range in Hz.
/// </summary>
[JsonInclude] public ulong StartFrequency { get; set; } = startFreq;
public ulong StartFrequency { get; set; } = startFreq;
/// <summary>
/// The upper bound of the tunable frequency range in Hz.
/// </summary>
[JsonInclude] public ulong EndFrequency { get; set; } = endFreq;
public ulong EndFrequency { get; set; } = endFreq;
}

[JsonConverter(typeof(JsonStringEnumConverter<IPMode>))]
Expand Down
8 changes: 1 addition & 7 deletions WirelessMicSuiteServer/JsonStringConverter.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
using static System.ComponentModel.TypeConverter;
using System.Collections;
using System.ComponentModel.Design.Serialization;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Reflection;
using System.Text.Json.Serialization;
using System.Text.Json;
using System;
Expand Down
14 changes: 11 additions & 3 deletions WirelessMicSuiteServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ public static void Main(string[] args)
WirelessMicManager micManager = new([
new ShureUHFRManager() { PollingPeriodMS = meterInterval }
]);
WebSocketAPIManager wsAPIManager = new(micManager, meterInterval);
if (cli.ParsedArgs.ContainsKey("--meters"))
Task.Run(() => MeterTask(micManager));
StartWebServer(args, micManager);
StartWebServer(args, micManager, wsAPIManager);
}

private static CommandLineOptions CreateCommandLineArgs(string[] args)
Expand All @@ -40,7 +41,7 @@ private static CommandLineOptions CreateCommandLineArgs(string[] args)
], args);
}

private static void StartWebServer(string[] args, WirelessMicManager micManager)
private static void StartWebServer(string[] args, WirelessMicManager micManager, WebSocketAPIManager wsAPIManager)
{
var builder = WebApplication.CreateBuilder(args);
//builder.Logging.ClearProviders();
Expand All @@ -66,7 +67,14 @@ private static void StartWebServer(string[] args, WirelessMicManager micManager)

app.UseAuthorization();

WebAPI.AddWebRoots(app, micManager);
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

WebAPI.AddWebRoots(app, micManager, wsAPIManager);

app.Run();
}
Expand Down
7 changes: 5 additions & 2 deletions WirelessMicSuiteServer/ShureUHFR/ShureUHFRManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ private void TXTask()
while (!txPipe.TryDequeue(out msg))
txAvailableSem.Wait(1000);
socket.SendTo(msg.Buffer, msg.endPoint);
msg.Dispose();
/*var msg = await txPipe.Reader.ReadAsync(cancellationToken);
foreach (var part in msg.Buffer)
await socket.SendAsync(part);*/
Expand Down Expand Up @@ -209,7 +210,7 @@ private void PingTask()
internal void SendMessage(ByteMessage message)
{
if (message.endPoint.Address == IPAddress.Any)
throw new ArgumentException();
throw new ArgumentException($"Specified message endpoint is IPAddress.Any, this is probably not intentional...");
txPipe.Enqueue(message);
txAvailableSem.Release();
}
Expand Down Expand Up @@ -244,7 +245,9 @@ enum ShureCommandType
REPORT,
SAMPLE,
NOTE,
NOTED
NOTED,
SCAN,
RFLEVEL
}

public readonly record struct ShureSNetHeader
Expand Down
41 changes: 33 additions & 8 deletions WirelessMicSuiteServer/ShureUHFR/ShureUHFRReceiver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public IPMode? IPMode
}
}
}
public MACAddress? MACAddres => macAddress;
public MACAddress? MACAddress => macAddress;

public event PropertyChangedEventHandler? PropertyChanged;

Expand Down Expand Up @@ -202,6 +202,16 @@ public void Receive(ReadOnlySpan<char> msg, ShureSNetHeader header)
// This is just an acknowledgement of the UPDATE command, we can safely ignore it...
return;
}
else if (msg.StartsWith("RFLEVEL"))
{
type = ShureCommandType.RFLEVEL;
msg = msg[7..];
}
else if (msg.StartsWith("SCAN"))
{
type = ShureCommandType.SCAN;
msg = msg[4..];
}
else
{
Log($"Unknown command type '{msg.ToString().Split(' ')[0]}'", LogSeverity.Warning);
Expand All @@ -221,9 +231,19 @@ public void Receive(ReadOnlySpan<char> msg, ShureSNetHeader header)
msg = msg[noteEnd..];
}

ReadOnlySpan<char> cmd = msg;
if (type == ShureCommandType.SCAN)
{
// Next is the command itself
msg = msg[1..];
int scmdEnd = msg.IndexOf(' ');
cmd = scmdEnd == -1 ? msg : msg[..scmdEnd];
msg = msg[scmdEnd..];
}

// This is followed by 1 or 2 for the receiver number
int receiver;
if (msg.Length < 3)
if (msg.Length < 2)
{
Log($"Incomplete message, missing receiver number: '{fullMsg}'", LogSeverity.Warning);
return;
Expand All @@ -242,12 +262,17 @@ public void Receive(ReadOnlySpan<char> msg, ShureSNetHeader header)
{
receiver = -1;
}
msg = msg[1..];
if (msg.Length > 0)
msg = msg[1..];

if (type != ShureCommandType.SCAN)
{
// Next is the command itself
int cmdEnd = msg.IndexOf(' ');
cmd = cmdEnd == -1 ? msg : msg[..cmdEnd];
msg = msg[(cmdEnd + 1)..];
}

// Next is the command itself
int cmdEnd = msg.IndexOf(' ');
var cmd = cmdEnd == -1 ? msg : msg[..cmdEnd];
msg = msg[(cmdEnd+1)..];
if (receiver == -1)
ParseCommand(type, cmd, msg, fullMsg);
else
Expand Down Expand Up @@ -319,7 +344,7 @@ private void ParseCommand(ShureCommandType type, ReadOnlySpan<char> cmd, ReadOnl
try
{
macAddress = new MACAddress(args);
OnPropertyChanged(nameof(MACAddres));
OnPropertyChanged(nameof(MACAddress));
} catch
{
CommandError(fullMsg, "Expected a MAC address in the form aa:bb:cc:dd:ee:ff!");
Expand Down
Loading

0 comments on commit ff20f7b

Please sign in to comment.