HamBook – Rev 58
?pathlinks?
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using HamBook.Properties;
using RJCP.IO.Ports;
using Serilog;
namespace HamBook.Radios
{
public class CatAssemblies : IDisposable
{
private readonly ConcurrentDictionary<string, Cat> _catCommands;
private readonly string _radio;
private readonly SemaphoreSlim _semaphoreSlim;
private readonly SerialPortStream _serialPort;
private int _count;
private CatAssemblies()
{
_catCommands = new ConcurrentDictionary<string, Cat>();
_semaphoreSlim = new SemaphoreSlim(1, 1);
}
public CatAssemblies(SerialPortStream serialPort, string radio) : this()
{
_serialPort = serialPort;
_radio = radio;
Load(_radio);
}
public int Count => _count;
public void Dispose()
{
Unload();
}
private void Load(string radio)
{
Interlocked.Exchange(ref _count, 0);
foreach (var type in Assembly.GetExecutingAssembly()
.GetTypes()
.Where(type => type.IsSubclassOf(typeof(Cat)))
.Where(type =>
type.GetCustomAttribute<RadioAttribute>() != null &&
type.GetCustomAttribute<RadioAttribute>().Radio == radio))
try
{
var catCommand = (Cat)type
.GetConstructor(new[] { typeof(SerialPortStream) })?.Invoke(new object[] { _serialPort });
if (catCommand == null) throw new ArgumentException(Resources.Could_not_create_assembly);
if (!_catCommands.TryAdd(catCommand.Name, catCommand))
{
Log.Warning(Resources.Unable_to_register_assembly, catCommand.Name);
catCommand.Dispose();
continue;
}
//BindEventHandlers(command);
Interlocked.Increment(ref _count);
}
catch (Exception exception)
{
Log.Error(exception, Resources.Could_not_instantiate_assembly, type);
}
Log.Information(Resources.Registering_commands, Count);
}
private void Unload()
{
// Dispose all command assemblies.
var list = new List<Cat>(_catCommands.Values);
for (var i = 0; i < list.Count; ++i)
try
{
//UnbindEventHandlers(list[i]);
if (list[i] != null)
{
Log.Debug(Resources.Disposing_assembly, list[i].GetType().Name);
list[i]
.Dispose();
list[i] = null;
}
}
catch (NullReferenceException)
{
// Already removed.
}
catch (ObjectDisposedException)
{
list[i] = null;
}
catch (Exception exception)
{
Log.Error(exception, Resources.Error_encountered_while_disposing_object);
}
_catCommands.Clear();
}
public bool CatParse<T>(string command, object[] param, out T output)
{
if (!_catCommands.TryGetValue(command, out var catCommand))
throw new CatCommandException(Resources.CAT_command_not_found, command);
var methodInfo = catCommand.GetType().GetMethod("Parse");
if (methodInfo == null)
{
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "Parse");
}
output = default;
try
{
output = (T)methodInfo.Invoke(catCommand, param);
}
catch
{
return false;
}
return true;
}
public T CatGetDefault<T>(string command, object[] param)
{
_semaphoreSlim.Wait();
try
{
if (!_serialPort.IsOpen) _serialPort.Open();
if (_catCommands.TryGetValue(command, out var catCommand))
{
var methodInfo = catCommand.GetType().GetMethod("GetDefault");
if (methodInfo != null)
{
return (T)methodInfo.Invoke(catCommand, param);
}
}
}
finally
{
if (_serialPort.IsOpen)
{
_serialPort.Flush();
_serialPort.Close();
}
_semaphoreSlim.Release();
}
return default;
}
public void CatSet(string command, object[] param)
{
_semaphoreSlim.Wait();
try
{
if (!_serialPort.IsOpen) _serialPort.Open();
if (!_catCommands.TryGetValue(command, out var catCommand))
throw new CatCommandException(Resources.CAT_command_not_found, command);
var methodInfo = catCommand.GetType().GetMethod("Set") ??
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "Set");
methodInfo.Invoke(catCommand, param);
}
finally
{
if (_serialPort.IsOpen)
{
_serialPort.Flush();
_serialPort.Close();
}
_semaphoreSlim.Release();
}
}
public async Task<TU> CatSetAsync<T, TU>(string command, object[] param, CancellationToken cancellationToken)
{
await _semaphoreSlim.WaitAsync(cancellationToken);
try
{
if (!_serialPort.IsOpen) _serialPort.Open();
if (!_catCommands.TryGetValue(command, out var catCommand))
throw new CatCommandException(Resources.CAT_command_not_found, command);
var methodInfo = catCommand.GetType().GetMethod("SetAsync") ??
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "SetAsync");
if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null)
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "SetAsync");
var parameters = new List<object>();
parameters.AddRange(param);
parameters.Add(cancellationToken);
var result = await (Task<TU>)methodInfo.Invoke(catCommand, parameters.ToArray());
return result;
}
finally
{
if (_serialPort.IsOpen)
{
await _serialPort.FlushAsync(cancellationToken);
_serialPort.Close();
}
_semaphoreSlim.Release();
}
}
public void CatWrite<T>(string command, object[] param)
{
_semaphoreSlim.Wait();
try
{
if (!_serialPort.IsOpen) _serialPort.Open();
if (!_catCommands.TryGetValue(command, out var catCommand))
throw new CatCommandException(Resources.CAT_command_not_found, command);
var methodInfo = catCommand.GetType().GetMethod("Write") ??
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "Write");
methodInfo.Invoke(catCommand, param);
}
finally
{
if (_serialPort.IsOpen)
{
_serialPort.Flush();
_serialPort.Close();
}
_semaphoreSlim.Release();
}
}
public async Task CatWriteAsync<T>(string command, object[] param, CancellationToken cancellationToken)
{
await _semaphoreSlim.WaitAsync(cancellationToken);
try
{
if (!_serialPort.IsOpen) _serialPort.Open();
if (!_catCommands.TryGetValue(command, out var catCommand))
throw new CatCommandException(Resources.CAT_command_not_found, command);
var methodInfo = catCommand.GetType().GetMethod("WriteAsync") ??
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync");
if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null)
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync");
var parameters = new List<object>();
parameters.AddRange(param);
parameters.Add(cancellationToken);
await (Task)methodInfo.Invoke(catCommand, parameters.ToArray());
}
finally
{
if (_serialPort.IsOpen)
{
await _serialPort.FlushAsync(cancellationToken);
_serialPort.Close();
}
_semaphoreSlim.Release();
}
}
public async Task CatWriteAsyncManual<T>(string command, object[] param, CancellationToken cancellationToken)
{
await _semaphoreSlim.WaitAsync(cancellationToken);
try
{
if (!_serialPort.IsOpen) _serialPort.Open();
if (!_catCommands.TryGetValue(command, out var catCommand))
throw new CatCommandException(Resources.CAT_command_not_found, command);
var methodInfo = catCommand.GetType().GetMethod("WriteAsync") ??
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync");
if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null)
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync");
var parameters = new List<object>();
parameters.AddRange(param);
parameters.Add(cancellationToken);
await (Task)methodInfo.Invoke(catCommand, parameters.ToArray());
}
finally
{
if (_serialPort.IsOpen)
{
await _serialPort.FlushAsync(cancellationToken);
}
_semaphoreSlim.Release();
}
}
public async Task CatWriteAsync(string command, object[] param, CancellationToken cancellationToken)
{
await _semaphoreSlim.WaitAsync(cancellationToken);
try
{
if (!_serialPort.IsOpen) _serialPort.Open();
if (!_catCommands.TryGetValue(command, out var catCommand))
throw new CatCommandException(Resources.CAT_command_not_found, command);
var methodInfo = catCommand.GetType().GetMethod("WriteAsync") ??
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync");
if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null)
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync");
var parameters = new List<object>();
parameters.AddRange(param);
parameters.Add(cancellationToken);
await (Task)methodInfo.Invoke(catCommand, parameters.ToArray());
}
finally
{
if (_serialPort.IsOpen)
{
await _serialPort.FlushAsync(cancellationToken);
_serialPort.Close();
}
_semaphoreSlim.Release();
}
}
public T CatRead<T>(string command, object[] param)
{
_semaphoreSlim.Wait();
try
{
if (!_serialPort.IsOpen) _serialPort.Open();
if (!_catCommands.TryGetValue(command, out var catCommand))
throw new CatCommandException(Resources.CAT_command_not_found, command);
var methodInfo = catCommand.GetType().GetMethod("Read");
if (methodInfo != null) return (T)methodInfo.Invoke(catCommand, param);
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "Read");
}
finally
{
if (_serialPort.IsOpen)
{
_serialPort.Flush();
_serialPort.Close();
}
_semaphoreSlim.Release();
}
}
public async Task<T> CatReadAsync<T>(string command, object[] param, CancellationToken cancellationToken)
{
await _semaphoreSlim.WaitAsync(cancellationToken);
try
{
if (!_serialPort.IsOpen) _serialPort.Open();
if (_catCommands.TryGetValue(command, out var catCommand))
{
var methodInfo = catCommand.GetType().GetMethod("ReadAsync") ??
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "ReadAsync");
if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null)
throw new CatCommandException(Resources.CAT_command_method_not_found, command, "ReadAsync");
var parameters = new List<object>();
parameters.AddRange(param);
parameters.Add(cancellationToken);
var result = await (Task<T>)methodInfo.Invoke(catCommand, parameters.ToArray());
return result;
}
throw new CatCommandException(Resources.CAT_command_not_found, command);
}
finally
{
if (_serialPort.IsOpen)
{
await _serialPort.FlushAsync(cancellationToken);
_serialPort.Close();
}
_semaphoreSlim.Release();
}
}
}
}
Generated by GNU Enscript 1.6.5.90.