Skip to content

Commit

Permalink
Added API setters & other API improvements:
Browse files Browse the repository at this point in the history
 - Increased default receiver disconnect timeout
 - Metering rate is now customisable through a command line option
 - Added command line parser
 - Converted serializable struct fields to properties
 - Improved API doc/Swagger
 - Fixed IP address and MAC address string constructor bugs
 - Default metering interval reduced to 50ms
 - Added generic web API setter methods for wireless mics and receivers
  • Loading branch information
space928 committed Jun 26, 2024
1 parent ad1ba01 commit 40df367
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 152 deletions.
139 changes: 139 additions & 0 deletions WirelessMicSuiteServer/CommandLineOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System.Reflection;

namespace WirelessMicSuiteServer;

public class CommandLineOptions
{
private Dictionary<string, CommandLineOption> options;
private Dictionary<string, object?> parsedArgs;

public Dictionary<string, object?> ParsedArgs => parsedArgs;

public CommandLineOptions(CommandLineOption[] options, string[]? args)
{
this.parsedArgs = [];
this.options = new(
options.Select(x => new KeyValuePair<string, CommandLineOption>(x.key, x))
.Concat(
options.Where(x=>x.alias != null)
.Select(x => new KeyValuePair<string, CommandLineOption>(x.alias!, x))));

this.options.TryAdd("--help", new("--help", action: _=>PrintHelp()));

if (args != null )
ParseArgs(args);
}

private readonly ILogger logger = Program.LoggerFac.CreateLogger<CommandLineOptions>();
public void Log(string? message, LogSeverity severity = LogSeverity.Info)
{
logger.Log(message, severity);
}

public void ParseArgs(string[] args)
{
CommandLineOption? option = null;
List<object> tmpList = [];
foreach (var arg in args)
{
if (options.TryGetValue(arg, out var nOption))
{
AddParsedArg(option, tmpList);

option = nOption;
continue;
}

if (option == null)
{
Log($"Unrecognised command line argument '{arg}'!", LogSeverity.Error);
Console.WriteLine();
PrintHelp();
return;
}

try
{
switch (option.Value.argType)
{
case CommandLineArgType.None:
break;
case CommandLineArgType.String:
tmpList.Add(arg);
break;
case CommandLineArgType.Int:
tmpList.Add(int.Parse(arg));
break;
case CommandLineArgType.Uint:
tmpList.Add(uint.Parse(arg));
break;
case CommandLineArgType.Path:
if (!Path.Exists(arg))
throw new ArgumentException($"Path '{arg}' does not exist!");
tmpList.Add(arg);
break;
}
}
catch
{
Log($"Couldn't parse '{arg}' as {option.Value.argType}!", LogSeverity.Error);
Console.WriteLine();
PrintHelp();
return;
}

if (!option.Value.multipleArguments)
option = null;
}

AddParsedArg(option, tmpList);

void AddParsedArg(CommandLineOption? option, List<object> tmpList)
{
if (option is CommandLineOption opt)
{
opt.action?.Invoke(opt.multipleArguments ? tmpList.ToArray() : tmpList.FirstOrDefault());
parsedArgs.Add(option.Value.key, opt.multipleArguments ? tmpList.ToArray() : tmpList.FirstOrDefault());
tmpList.Clear();
}
}
}

public void PrintHelp()
{
var assembly = Assembly.GetExecutingAssembly();
Console.WriteLine($"##### Wireless Mic Suite Server #####");
Console.WriteLine($"# version: {assembly.GetName().Version}");
Console.WriteLine($"# ");
Console.WriteLine($"# Command line options: ");
foreach (var opt in options.Values)
{
Console.WriteLine($"\t{opt.key}{(opt.alias != null?", " + opt.alias:"")} " +
$"{(opt.argType != CommandLineArgType.None ? "<"+opt.argType+">":"")}{(opt.multipleArguments?", ...":"")}");
Console.WriteLine($"\t\t{opt.help}");
Console.WriteLine();
}
}
}

public struct CommandLineOption(string key, string? alias = null, string? help = null,
CommandLineArgType argType = CommandLineArgType.None, bool multipleArguments = false,
Action<object?>? action = null)
{
public string key = key;
public string? alias = alias;
public string? help = help;
public CommandLineArgType argType = argType;
public bool multipleArguments = multipleArguments;
//public bool positional;
public Action<object?>? action = action;
}

public enum CommandLineArgType
{
None,
String,
Int,
Uint,
Path
}
33 changes: 28 additions & 5 deletions WirelessMicSuiteServer/IWirelessMicReceiver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,13 @@ public interface IWirelessMic : INotifyPropertyChanged
/// <param name="audioLevel"></param>
public struct MeteringData(float rssiA, float rssiB, float audioLevel)
{
[JsonInclude] public float rssiA = rssiA;
[JsonInclude] public float rssiB = rssiB;
[JsonInclude] public float audioLevel = audioLevel;
[JsonIgnore] public float rssiA = rssiA;
[JsonIgnore] public float rssiB = rssiB;
[JsonIgnore] public float audioLevel = audioLevel;

public readonly float RssiA => rssiA;
public readonly float RssiB => rssiB;
public readonly float AudioLevel => audioLevel;
}

/// <summary>
Expand Down Expand Up @@ -228,16 +232,21 @@ public void StopMetering()
}
}

/// <summary>
/// A frequency range in Hz.
/// </summary>
/// <param name="startFreq">The lower bound of the tunable frequency range in Hz.</param>
/// <param name="endFreq">The upper bound of the tunable frequency range in Hz.</param>
public struct FrequencyRange(ulong startFreq, ulong endFreq)
{
/// <summary>
/// The lower bound of the tunable frequency range in Hz.
/// </summary>
[JsonInclude] public ulong startFrequency = startFreq;
[JsonInclude] public ulong StartFrequency { get; set; } = startFreq;
/// <summary>
/// The upper bound of the tunable frequency range in Hz.
/// </summary>
[JsonInclude] public ulong endFrequency = endFreq;
[JsonInclude] public ulong EndFrequency { get; set; } = endFreq;
}

[JsonConverter(typeof(JsonStringEnumConverter<IPMode>))]
Expand All @@ -247,6 +256,9 @@ public enum IPMode
Manual
}

/// <summary>
/// Represents an IPv4 address.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
[JsonConverter(typeof(JsonStringConverter<IPv4Address>))]
public struct IPv4Address
Expand Down Expand Up @@ -281,6 +293,10 @@ public IPv4Address(IPAddress address)
throw new ArgumentException($"Failed to convert IP address '{address}' to IPv4Address!");
}

/// <inheritdoc cref="IPv4Address(ReadOnlySpan{char})"/>
[JsonConstructor]
public IPv4Address(string str) : this(str.AsSpan()) { }

/// <summary>
/// Parse an IPv4 address in the form 'aaa.bbb.ccc.ddd'.
/// </summary>
Expand All @@ -306,6 +322,9 @@ public override readonly string ToString()
}
}

/// <summary>
/// Represents a MAC address.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
[JsonConverter(typeof(JsonStringConverter<MACAddress>))]
public struct MACAddress
Expand Down Expand Up @@ -334,6 +353,10 @@ public MACAddress(byte a, byte b, byte c, byte d, byte e, byte f)
this.f = f;
}

/// <inheritdoc cref="MACAddress(ReadOnlySpan{char})"/>
[JsonConstructor]
public MACAddress(string str) : this(str.AsSpan()) { }

/// <summary>
/// Parse a MAC address in the form 'aa:bb:cc:dd:ee:ff'.
/// </summary>
Expand Down
10 changes: 4 additions & 6 deletions WirelessMicSuiteServer/JsonStringConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ public JsonStringConverter()
public sealed override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
if (typeToConvert != typeof(T))
{
throw new ArgumentOutOfRangeException();
}

return new StringConverter<T>();
}
Expand All @@ -40,10 +38,10 @@ public JsonStringConverter()
public StringConverter()
{
var str = typeof(T).GetConstructor([typeof(string)]);
var spn = typeof(T).GetConstructor([typeof(ReadOnlySpan<char>)]);
if (spn != null)
strConstructor = spn;
else if (str != null)
//var spn = typeof(T).GetConstructor([typeof(ReadOnlySpan<char>)]);
//if (spn != null)
// strConstructor = spn;
/*else*/ if (str != null)
strConstructor = str;
else
throw new ArgumentException("Target type must have a constructor which takes a single string as a parameter!");
Expand Down
124 changes: 0 additions & 124 deletions WirelessMicSuiteServer/MessagePipe.cs

This file was deleted.

Loading

0 comments on commit 40df367

Please sign in to comment.