This commit is contained in:
Dan Clark
2025-02-09 13:51:25 +00:00
parent f2e501454e
commit 0afe621f59
22 changed files with 147 additions and 122 deletions
+9 -5
View File
@@ -197,16 +197,20 @@ public static class IHostBuilderExtension
return builder; return builder;
} }
public static IHostBuilder ConfigureSerial<TConfiguration, TSerialReader, TContent>(this IHostBuilder hostBuilder, public static IHostBuilder ConfigureMicroControllers(this IHostBuilder hostBuilder, Action<IMicroControllerBuilder> builderDelegate)
Action<HostBuilderContext> configureDelegate) where TSerialReader : SerialReader<TContent>
where TConfiguration : ISerialConfiguration, new()
{ {
hostBuilder.ConfigureServices((hostBuilderContext, serviceCollection) => hostBuilder.ConfigureServices((hostBuilderContext, serviceCollection) =>
{ {
configureDelegate.Invoke(hostBuilderContext); MicroControllerBuilder? builder = new();
builderDelegate.Invoke(builder);
serviceCollection.TryAddSingleton<ISerialFactory, SerialFactory>(); serviceCollection.TryAddSingleton<ISerialFactory, SerialFactory>();
serviceCollection.AddSingleton(provider => provider.GetService<ISerialFactory>()!.Create<TSerialReader, TContent>(provider.GetService<IOptionsMonitor<TConfiguration>>()!.CurrentValue)); serviceCollection.TryAddSingleton<IMicroControllerContextFactory, MicroControllerContextFactory>();
foreach (IMicroControllerBuilderConfiguration configuration in builder.Configurations)
{
serviceCollection.AddSingleton(provider => configuration.Factory.Invoke(provider) ?? throw new NullReferenceException());
}
}); });
return hostBuilder; return hostBuilder;
@@ -0,0 +1,9 @@
namespace Toolkit.Foundation;
public interface IMicroControllerContextFactory
{
IMicroControllerContext<TRead, TEvent>? Create<TConfiguration, TReader, TRead, TEvent>(IReadOnlyCollection<IMicroControllerModuleDescriptor> modules)
where TConfiguration : ISerialConfiguration
where TReader : SerialReader<TRead>
where TEvent : ISerialEventArgs<TRead>;
}
@@ -1,12 +1,11 @@
using Microsoft.Extensions.Configuration; namespace Toolkit.Foundation;
namespace Toolkit.Foundation; public interface IMicroControllerBuilder
public interface IMicrocontrollerBuilder
{ {
IReadOnlyCollection<IMicrocontrollerBuilderConfiguration> Configurations { get; } IReadOnlyCollection<IMicroControllerBuilderConfiguration> Configurations { get; }
IMicrocontrollerBuilderConfiguration<TConfiguration, TSerialReader, TRead, TReadDeserializer> Add<TConfiguration, TSerialReader, TRead, TReadDeserializer>(IConfiguration configuration) IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent> Add<TConfiguration, TReader, TRead, TEvent>()
where TConfiguration : IMicrocontrollerConfiguration, new() where TConfiguration : ISerialConfiguration
where TSerialReader : SerialReader<TRead> where TReadDeserializer : IMicrocontrollerModuleDeserializer<TRead>, new(); where TReader : SerialReader<TRead>
where TEvent : ISerialEventArgs<TRead>;
} }
@@ -1,17 +1,19 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public interface IMicrocontrollerBuilderConfiguration public interface IMicroControllerBuilderConfiguration
{ {
IReadOnlyCollection<IMicrocontrollerModuleDescriptor> Modules { get; } IReadOnlyCollection<IMicroControllerModuleDescriptor> Modules { get; }
Func<IServiceProvider, IMicrocontrollerContext> Factory { get; } Func<IServiceProvider, IMicroControllerContext?> Factory { get; }
} }
public interface IMicrocontrollerBuilderConfiguration<TConfiguration, TSerialReader, TRead, TReadDeserializer> : public interface IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, IEvent> :
IMicrocontrollerBuilderConfiguration where TConfiguration : IMicrocontrollerConfiguration, new() IMicroControllerBuilderConfiguration
where TSerialReader : SerialReader<TRead> where TReadDeserializer : IMicrocontrollerModuleDeserializer<TRead>, new() where TConfiguration : ISerialConfiguration
where TReader : SerialReader<TRead>
where IEvent : ISerialEventArgs<TRead>
{ {
IMicrocontrollerBuilderConfiguration<TConfiguration, TSerialReader, TRead, TReadDeserializer> AddModule<TModule>() IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, IEvent> AddModule<TModule>()
where TModule : IMicrocontrollerModule, new(); where TModule : IMicroControllerModule, new();
} }
@@ -1,4 +0,0 @@
namespace Toolkit.Foundation;
public interface IMicrocontrollerConfiguration :
ISerialConfiguration;
@@ -1,6 +1,7 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public interface IMicrocontrollerContext<TRead, TModuleDeserializer> : public interface IMicroControllerContext<TRead, TEvent> :
IMicrocontrollerContext where TModuleDeserializer : IMicrocontrollerModuleDeserializer<TRead>, new(); IMicroControllerContext
where TEvent : ISerialEventArgs<TRead>;
public interface IMicrocontrollerContext; public interface IMicroControllerContext;
@@ -1,7 +0,0 @@
namespace Toolkit.Foundation;
public interface IMicrocontrollerFactory
{
IMicrocontrollerContext<TRead, TReadDeserializer> Create<TSerialReader, TRead, TReadDeserializer>(IMicrocontrollerConfiguration configuration, IReadOnlyCollection<IMicrocontrollerModuleDescriptor> modules)
where TSerialReader : SerialReader<TRead> where TReadDeserializer : IMicrocontrollerModuleDeserializer<TRead>, new();
}
+1 -1
View File
@@ -1,3 +1,3 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public interface IMicrocontrollerModule; public interface IMicroControllerModule;
@@ -1,12 +1,13 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public interface IMicrocontrollerModuleDescriptor<TModule> : public interface IMicroControllerModuleDescriptor<TModule> :
IMicrocontrollerModuleDescriptor where TModule : IMicrocontrollerModule IMicroControllerModuleDescriptor
where TModule : IMicroControllerModule
{ {
Func<TModule>? Factory { get; } Func<TModule>? Factory { get; }
} }
public interface IMicrocontrollerModuleDescriptor public interface IMicroControllerModuleDescriptor
{ {
Type Type { get; } Type Type { get; }
} }
@@ -1,6 +0,0 @@
namespace Toolkit.Foundation;
public interface IMicrocontrollerModuleDeserializer<TRead>
{
public TRead? Read { get; set; }
}
+3 -2
View File
@@ -1,7 +1,8 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public interface ISerialContext<TSerialReader, TContent> : public interface ISerialContext<TReader, TRead> :
ISerialContext where TSerialReader : SerialReader<TContent>; ISerialContext
where TReader : SerialReader<TRead>;
public interface ISerialContext public interface ISerialContext
{ {
+3
View File
@@ -0,0 +1,3 @@
namespace Toolkit.Foundation;
public interface ISerialEventArgs<TRead>;
+3 -2
View File
@@ -2,6 +2,7 @@
public interface ISerialFactory public interface ISerialFactory
{ {
ISerialContext<TSerialReader, TContent> Create<TSerialReader, TContent>(ISerialConfiguration configuration) ISerialContext<TReader, TRead>? Create<TConfiguration, TReader, TRead>()
where TSerialReader : SerialReader<TContent>; where TConfiguration : ISerialConfiguration
where TReader : SerialReader<TRead>;
} }
@@ -0,0 +1,35 @@
using Microsoft.Extensions.DependencyInjection;
namespace Toolkit.Foundation;
public class MicroControllerContextFactory(IServiceProvider provider,
IServiceFactory factory,
ISerialFactory serialFactory) :
IMicroControllerContextFactory
{
private readonly Dictionary<ISerialConfiguration, IMicroControllerContext> cache = [];
public IMicroControllerContext<TRead, THandler>? Create<TConfiguration, TReader, TRead, THandler>(IReadOnlyCollection<IMicroControllerModuleDescriptor> modules)
where TConfiguration : ISerialConfiguration
where TReader : SerialReader<TRead>
where THandler : ISerialEventArgs<TRead>
{
if (provider.GetRequiredService<TConfiguration>() is TConfiguration configuration)
{
if (cache.TryGetValue(configuration, out IMicroControllerContext? context))
{
return (IMicroControllerContext<TRead, THandler>)context;
}
if (serialFactory.Create<TConfiguration, TReader, TRead>() is ISerialContext<TReader, TRead> serialContext)
{
context = factory.Create<MicroControllerContext<TRead, THandler>>(modules, serialContext);
cache.Add(configuration, context);
return (IMicroControllerContext<TRead, THandler>)context;
}
}
return default;
}
}
+11 -12
View File
@@ -1,22 +1,21 @@
using Microsoft.Extensions.Configuration; using System.Collections.ObjectModel;
using System.Collections.ObjectModel;
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public class MicrocontrollerBuilder : public class MicroControllerBuilder :
IMicrocontrollerBuilder IMicroControllerBuilder
{ {
private readonly List<IMicrocontrollerBuilderConfiguration> configurations = []; private readonly List<IMicroControllerBuilderConfiguration> configurations = [];
public IReadOnlyCollection<IMicrocontrollerBuilderConfiguration> Configurations => public IReadOnlyCollection<IMicroControllerBuilderConfiguration> Configurations =>
new ReadOnlyCollection<IMicrocontrollerBuilderConfiguration>(configurations); new ReadOnlyCollection<IMicroControllerBuilderConfiguration>(configurations);
public IMicrocontrollerBuilderConfiguration<TConfiguration, TSerialReader, TRead, TReadDeserializer> Add<TConfiguration, TSerialReader, TRead, TReadDeserializer>(IConfiguration configuration) public IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent> Add<TConfiguration, TReader, TRead, TEvent>()
where TConfiguration : IMicrocontrollerConfiguration, new() where TConfiguration : ISerialConfiguration
where TSerialReader : SerialReader<TRead> where TReader : SerialReader<TRead>
where TReadDeserializer : IMicrocontrollerModuleDeserializer<TRead>, new() where TEvent : ISerialEventArgs<TRead>
{ {
MicrocontrollerBuilderConfiguration<TConfiguration, TSerialReader, TRead, TReadDeserializer>? builderConfiguration = new(configuration); MicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent>? builderConfiguration = new();
configurations.Add(builderConfiguration); configurations.Add(builderConfiguration);
return builderConfiguration; return builderConfiguration;
@@ -1,24 +1,25 @@
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public class MicrocontrollerBuilderConfiguration<TConfiguration, TSerialReader, TRead, TReadDeserializer>(IConfiguration configuration) : public class MicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent> :
IMicrocontrollerBuilderConfiguration<TConfiguration, TSerialReader, TRead, TReadDeserializer> IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent>
where TConfiguration : IMicrocontrollerConfiguration, new() where TConfiguration : ISerialConfiguration
where TSerialReader : SerialReader<TRead> where TReadDeserializer : IMicrocontrollerModuleDeserializer<TRead>, new() where TReader : SerialReader<TRead>
where TEvent : ISerialEventArgs<TRead>
{ {
private readonly List<IMicrocontrollerModuleDescriptor> modules = new(); private readonly List<IMicroControllerModuleDescriptor> modules = [];
public Func<IServiceProvider, IMicrocontrollerContext> Factory => (IServiceProvider provider) => provider.GetService<IMicrocontrollerFactory>()!.Create<TSerialReader, TRead, TReadDeserializer>(configuration.Get<TConfiguration>(), Modules); public Func<IServiceProvider, IMicroControllerContext?> Factory => (IServiceProvider provider) => provider.GetService<IMicroControllerContextFactory>()!
.Create<TConfiguration, TReader, TRead, TEvent>(Modules);
public IReadOnlyCollection<IMicrocontrollerModuleDescriptor> Modules => new ReadOnlyCollection<IMicrocontrollerModuleDescriptor>(modules); public IReadOnlyCollection<IMicroControllerModuleDescriptor> Modules => new ReadOnlyCollection<IMicroControllerModuleDescriptor>(modules);
public IMicrocontrollerBuilderConfiguration<TConfiguration, TSerialReader, TRead, TReadDeserializer> AddModule<TModule>() public IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent> AddModule<TModule>()
where TModule : IMicrocontrollerModule, new() where TModule : IMicroControllerModule, new()
{ {
modules.Add(new MicrocontrollerModuleDescriptor<TModule>()); modules.Add(new MicroControllerModuleDescriptor<TModule>());
return this; return this;
} }
} }
@@ -2,8 +2,8 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public class MicrocontrollerConfiguration : public class MicroControllerConfiguration :
IMicrocontrollerConfiguration ISerialConfiguration
{ {
[NotNull] [NotNull]
public string? PortName { get; set; } public string? PortName { get; set; }
+3 -2
View File
@@ -2,10 +2,11 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public class MicrocontrollerContext<TRead, TReadDeserializer>(IReadOnlyCollection<IMicrocontrollerModuleDescriptor> modules, public class MicroControllerContext<TRead, TEvent>(IReadOnlyCollection<IMicroControllerModuleDescriptor> modules,
IMessenger messenger, IMessenger messenger,
ISerialContext serialContext) : ISerialContext serialContext) :
IMicrocontrollerContext<TRead, TReadDeserializer> where TReadDeserializer : IMicrocontrollerModuleDeserializer<TRead>, new() IMicroControllerContext<TRead, TEvent>
where TEvent : ISerialEventArgs<TRead>
{ {
public async Task InitializeAsync() public async Task InitializeAsync()
{ {
@@ -1,23 +0,0 @@
namespace Toolkit.Foundation;
public class MicrocontrollerFactory(IServiceFactory factory,
ISerialFactory serialFactory) :
IMicrocontrollerFactory
{
private readonly Dictionary<ISerialConfiguration, IMicrocontrollerContext> cache = new();
public IMicrocontrollerContext<TRead, TReadDeserializer> Create<TSerialReader, TRead, TReadDeserializer>(IMicrocontrollerConfiguration configuration, IReadOnlyCollection<IMicrocontrollerModuleDescriptor> modules) where TSerialReader : SerialReader<TRead> where TReadDeserializer : IMicrocontrollerModuleDeserializer<TRead>, new()
{
if (cache.TryGetValue(configuration, out IMicrocontrollerContext? context))
{
return (IMicrocontrollerContext<TRead, TReadDeserializer>)context;
}
ISerialContext<TSerialReader, TRead> serialContext = serialFactory.Create<TSerialReader, TRead>(configuration);
context = factory.Create<MicrocontrollerContext<TRead, TReadDeserializer>>(modules, serialContext);
cache.Add(configuration, context);
return (IMicrocontrollerContext<TRead, TReadDeserializer>)context;
}
}
@@ -1,7 +1,7 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public record MicrocontrollerModuleDescriptor<TModule> : public record MicroControllerModuleDescriptor<TModule> :
IMicrocontrollerModuleDescriptor<TModule> where TModule : IMicrocontrollerModule, new() IMicroControllerModuleDescriptor<TModule> where TModule : IMicroControllerModule, new()
{ {
public Type Type => typeof(TModule); public Type Type => typeof(TModule);
+15 -7
View File
@@ -1,18 +1,23 @@
using System.IO.Ports; using Microsoft.Extensions.DependencyInjection;
using System.IO.Ports;
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public class SerialFactory(IServiceFactory factory) : public class SerialFactory(IServiceProvider provider,
IServiceFactory factory) :
ISerialFactory ISerialFactory
{ {
private readonly Dictionary<ISerialConfiguration, ISerialContext> cache = []; private readonly Dictionary<ISerialConfiguration, ISerialContext> cache = [];
public ISerialContext<TSerialReader, TContent> Create<TSerialReader, TContent>(ISerialConfiguration configuration) public ISerialContext<TReader, TRead>? Create<TConfiguration, TReader, TRead>()
where TSerialReader : SerialReader<TContent> where TConfiguration : ISerialConfiguration
where TReader : SerialReader<TRead>
{
if (provider.GetRequiredService<TConfiguration>() is TConfiguration configuration)
{ {
if (cache.TryGetValue(configuration, out ISerialContext? context)) if (cache.TryGetValue(configuration, out ISerialContext? context))
{ {
return (ISerialContext<TSerialReader, TContent>)context; return (ISerialContext<TReader, TRead>)context;
} }
SerialPort serialPort = new(configuration.PortName, configuration.BaudRate) SerialPort serialPort = new(configuration.PortName, configuration.BaudRate)
@@ -23,9 +28,12 @@ public class SerialFactory(IServiceFactory factory) :
SerialConnection connection = new(serialPort); SerialConnection connection = new(serialPort);
SerialStreamer streamer = new(serialPort); SerialStreamer streamer = new(serialPort);
context = factory.Create<SerialContext<TSerialReader, TContent>>(connection, streamer); context = factory.Create<SerialContext<TReader, TRead>>(connection, streamer);
cache.Add(configuration, context); cache.Add(configuration, context);
return (ISerialContext<TSerialReader, TContent>)context; return (ISerialContext<TReader, TRead>)context;
}
return default;
} }
} }
+2 -2
View File
@@ -1,8 +1,8 @@
namespace Toolkit.Foundation; namespace Toolkit.Foundation;
public abstract class SerialReader<TContent>(Stream stream) public abstract class SerialReader<TRead>(Stream stream)
{ {
public Stream Stream { get; } = stream; public Stream Stream { get; } = stream;
public abstract IAsyncEnumerable<TContent> ReadAsync(); public abstract IAsyncEnumerable<TRead> ReadAsync();
} }