Refactor serials
This commit is contained in:
@@ -5,7 +5,6 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
|
|||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
using Microsoft.Extensions.FileProviders.Physical;
|
using Microsoft.Extensions.FileProviders.Physical;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
@@ -197,25 +196,39 @@ public static class IHostBuilderExtension
|
|||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IHostBuilder ConfigureMicroControllers(this IHostBuilder hostBuilder, Action<IMicroControllerBuilder> builderDelegate)
|
public static IHostBuilder AddSerial<TConfiguration, TReader, TRead, TEvent>(this IHostBuilder hostBuilder)
|
||||||
|
where TConfiguration : ISerialConfiguration
|
||||||
|
where TReader : SerialReader<TRead>
|
||||||
|
where TEvent : SerialEventArgs<TRead>, new()
|
||||||
{
|
{
|
||||||
hostBuilder.ConfigureServices((hostBuilderContext, serviceCollection) =>
|
hostBuilder.ConfigureServices((hostBuilderContext, serviceCollection) =>
|
||||||
{
|
{
|
||||||
MicroControllerBuilder? builder = new();
|
serviceCollection.TryAddSingleton<ISerialContextFactory, SerialContextFactory>();
|
||||||
|
serviceCollection.AddSingleton<ISerialContext<TReader, TRead, TEvent>>(provider => provider.GetRequiredService<ISerialContextFactory>().Create<TConfiguration, TReader, TRead, TEvent>()
|
||||||
builderDelegate.Invoke(builder);
|
?? throw new NullReferenceException());
|
||||||
serviceCollection.TryAddSingleton<ISerialFactory, SerialFactory>();
|
|
||||||
serviceCollection.TryAddSingleton<IMicroControllerContextFactory, MicroControllerContextFactory>();
|
|
||||||
|
|
||||||
foreach (IMicroControllerBuilderConfiguration configuration in builder.Configurations)
|
|
||||||
{
|
|
||||||
serviceCollection.AddSingleton(provider => configuration.Factory.Invoke(provider) ?? throw new NullReferenceException());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return hostBuilder;
|
return hostBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//public static IHostBuilder ConfigureSerials(this IHostBuilder hostBuilder, Action<ISerialBuilder> builderDelegate)
|
||||||
|
//{
|
||||||
|
// hostBuilder.ConfigureServices((hostBuilderContext, serviceCollection) =>
|
||||||
|
// {
|
||||||
|
// SerialBuilder? builder = new();
|
||||||
|
|
||||||
|
// builderDelegate.Invoke(builder);
|
||||||
|
// serviceCollection.TryAddSingleton<ISerialContextFactory, SerialContextFactory>();
|
||||||
|
|
||||||
|
// foreach (ISerialBuilderConfiguration configuration in builder.Configurations)
|
||||||
|
// {
|
||||||
|
// serviceCollection.AddSingleton(provider => configuration.Factory.Invoke(provider) ?? throw new NullReferenceException());
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return hostBuilder;
|
||||||
|
//}
|
||||||
|
|
||||||
public static IHostBuilder UseContentRoot(this IHostBuilder hostBuilder,
|
public static IHostBuilder UseContentRoot(this IHostBuilder hostBuilder,
|
||||||
string contentRoot,
|
string contentRoot,
|
||||||
bool createDirectory)
|
bool createDirectory)
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
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,11 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface IMicroControllerBuilder
|
|
||||||
{
|
|
||||||
IReadOnlyCollection<IMicroControllerBuilderConfiguration> Configurations { get; }
|
|
||||||
|
|
||||||
IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent> Add<TConfiguration, TReader, TRead, TEvent>()
|
|
||||||
where TConfiguration : ISerialConfiguration
|
|
||||||
where TReader : SerialReader<TRead>
|
|
||||||
where TEvent : ISerialEventArgs<TRead>;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface IMicroControllerBuilderConfiguration
|
|
||||||
{
|
|
||||||
IReadOnlyCollection<IMicroControllerModuleDescriptor> Modules { get; }
|
|
||||||
|
|
||||||
Func<IServiceProvider, IMicroControllerContext?> Factory { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, IEvent> :
|
|
||||||
IMicroControllerBuilderConfiguration
|
|
||||||
where TConfiguration : ISerialConfiguration
|
|
||||||
where TReader : SerialReader<TRead>
|
|
||||||
where IEvent : ISerialEventArgs<TRead>
|
|
||||||
{
|
|
||||||
|
|
||||||
IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, IEvent> AddModule<TModule>()
|
|
||||||
where TModule : IMicroControllerModule, new();
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface IMicroControllerContext<TRead, TEvent> :
|
|
||||||
IMicroControllerContext
|
|
||||||
where TEvent : ISerialEventArgs<TRead>;
|
|
||||||
|
|
||||||
public interface IMicroControllerContext;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface IMicroControllerModule;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface IMicroControllerModuleDescriptor<TModule> :
|
|
||||||
IMicroControllerModuleDescriptor
|
|
||||||
where TModule : IMicroControllerModule
|
|
||||||
{
|
|
||||||
Func<TModule>? Factory { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IMicroControllerModuleDescriptor
|
|
||||||
{
|
|
||||||
Type Type { get; }
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public interface ISerialContext<TReader, TRead> :
|
public interface ISerialContext<TReader, TRead, TEvent> :
|
||||||
ISerialContext
|
ISerialContext
|
||||||
where TReader : SerialReader<TRead>;
|
where TReader : SerialReader<TRead>
|
||||||
|
where TEvent : SerialEventArgs<TRead>, new();
|
||||||
|
|
||||||
|
|
||||||
public interface ISerialContext
|
public interface ISerialContext
|
||||||
{
|
{
|
||||||
void Open();
|
bool Open();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
public interface ISerialContextFactory
|
||||||
|
{
|
||||||
|
ISerialContext<TReader, TRead, TEvent>? Create<TConfiguration, TReader, TRead, TEvent>()
|
||||||
|
where TConfiguration : ISerialConfiguration
|
||||||
|
where TReader : SerialReader<TRead>
|
||||||
|
where TEvent : SerialEventArgs<TRead>, new();
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface ISerialEventArgs<TRead>;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface ISerialFactory
|
|
||||||
{
|
|
||||||
ISerialContext<TReader, TRead>? Create<TConfiguration, TReader, TRead>()
|
|
||||||
where TConfiguration : ISerialConfiguration
|
|
||||||
where TReader : SerialReader<TRead>;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface ISerialResponse
|
|
||||||
{
|
|
||||||
ISerialContext Context { get; }
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public class MicroControllerBuilder :
|
|
||||||
IMicroControllerBuilder
|
|
||||||
{
|
|
||||||
private readonly List<IMicroControllerBuilderConfiguration> configurations = [];
|
|
||||||
|
|
||||||
public IReadOnlyCollection<IMicroControllerBuilderConfiguration> Configurations =>
|
|
||||||
new ReadOnlyCollection<IMicroControllerBuilderConfiguration>(configurations);
|
|
||||||
|
|
||||||
public IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent> Add<TConfiguration, TReader, TRead, TEvent>()
|
|
||||||
where TConfiguration : ISerialConfiguration
|
|
||||||
where TReader : SerialReader<TRead>
|
|
||||||
where TEvent : ISerialEventArgs<TRead>
|
|
||||||
{
|
|
||||||
MicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent>? builderConfiguration = new();
|
|
||||||
configurations.Add(builderConfiguration);
|
|
||||||
|
|
||||||
return builderConfiguration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public class MicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent> :
|
|
||||||
IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent>
|
|
||||||
where TConfiguration : ISerialConfiguration
|
|
||||||
where TReader : SerialReader<TRead>
|
|
||||||
where TEvent : ISerialEventArgs<TRead>
|
|
||||||
{
|
|
||||||
private readonly List<IMicroControllerModuleDescriptor> 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 IMicroControllerBuilderConfiguration<TConfiguration, TReader, TRead, TEvent> AddModule<TModule>()
|
|
||||||
where TModule : IMicroControllerModule, new()
|
|
||||||
{
|
|
||||||
modules.Add(new MicroControllerModuleDescriptor<TModule>());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public class MicroControllerConfiguration :
|
|
||||||
ISerialConfiguration
|
|
||||||
{
|
|
||||||
[NotNull]
|
|
||||||
public string? PortName { get; set; }
|
|
||||||
|
|
||||||
public int BaudRate { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using CommunityToolkit.Mvvm.Messaging;
|
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public class MicroControllerContext<TRead, TEvent>(IReadOnlyCollection<IMicroControllerModuleDescriptor> modules,
|
|
||||||
IMessenger messenger,
|
|
||||||
ISerialContext serialContext) :
|
|
||||||
IMicroControllerContext<TRead, TEvent>
|
|
||||||
where TEvent : ISerialEventArgs<TRead>
|
|
||||||
{
|
|
||||||
public async Task InitializeAsync()
|
|
||||||
{
|
|
||||||
//eventAggregator.Subscribe<SerialResponse<TRead>>(OnEvent, null, args => args.Context.Equals(serialContext));
|
|
||||||
serialContext.Open();
|
|
||||||
|
|
||||||
await Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnEvent(SerialResponse<TRead> args)
|
|
||||||
{
|
|
||||||
//IMicrocontrollerModule? module = await messenger.SendAsync<IMicrocontrollerModule>(new TReadDeserializer { Read = args.Content }, modules);
|
|
||||||
//messenger.Send((dynamic?)module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public record MicroControllerModuleDescriptor<TModule> :
|
|
||||||
IMicroControllerModuleDescriptor<TModule> where TModule : IMicroControllerModule, new()
|
|
||||||
{
|
|
||||||
public Type Type => typeof(TModule);
|
|
||||||
|
|
||||||
public Func<TModule>? Factory => new(() => new TModule());
|
|
||||||
}
|
|
||||||
@@ -2,24 +2,42 @@
|
|||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public class SerialContext<TSerialReader, TContent>(IMessenger messenger,
|
public class SerialContext<TReader, TValue, TEvent>(IMessenger messenger,
|
||||||
ISerialConnection connection,
|
ISerialConnection connection,
|
||||||
ISerialStreamer serialStreamer) :
|
ISerialStreamer serialStreamer) :
|
||||||
ISerialContext<TSerialReader, TContent> where TSerialReader : SerialReader<TContent>
|
ISerialContext<TReader, TValue, TEvent>
|
||||||
|
where TReader : SerialReader<TValue>
|
||||||
|
where TEvent : SerialEventArgs<TValue>, new()
|
||||||
{
|
{
|
||||||
public async void Open()
|
public bool IsOpen { get; private set; }
|
||||||
{
|
|
||||||
if (connection.Open())
|
|
||||||
{
|
|
||||||
Stream stream = serialStreamer.Create();
|
|
||||||
|
|
||||||
if ((TSerialReader?)Activator.CreateInstance(typeof(TSerialReader), [stream]) is TSerialReader reader)
|
public bool Open()
|
||||||
|
{
|
||||||
|
if (!connection.Open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IsOpen = true;
|
||||||
|
|
||||||
|
_ = ReadAsync();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ReadAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using Stream stream = serialStreamer.Create();
|
||||||
|
if (Activator.CreateInstance(typeof(TReader), [stream]) is TReader reader)
|
||||||
{
|
{
|
||||||
await foreach (TContent content in reader.ReadAsync())
|
await foreach (TValue value in reader.ReadAsync())
|
||||||
{
|
{
|
||||||
messenger.Send(SerialResponse.Create(this, content));
|
messenger.Send(new SerialEventArgs<TValue> { Value = value });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
IsOpen = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,35 +3,35 @@ using System.IO.Ports;
|
|||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public class SerialFactory(IServiceProvider provider,
|
public class SerialContextFactory(IServiceProvider provider,
|
||||||
IServiceFactory factory) :
|
IServiceFactory factory) :
|
||||||
ISerialFactory
|
ISerialContextFactory
|
||||||
{
|
{
|
||||||
private readonly Dictionary<ISerialConfiguration, ISerialContext> cache = [];
|
private readonly Dictionary<ISerialConfiguration, ISerialContext> cache = [];
|
||||||
|
|
||||||
public ISerialContext<TReader, TRead>? Create<TConfiguration, TReader, TRead>()
|
public ISerialContext<TReader, TValue, TEvent>? Create<TConfiguration, TReader, TValue, TEvent>()
|
||||||
where TConfiguration : ISerialConfiguration
|
where TConfiguration : ISerialConfiguration
|
||||||
where TReader : SerialReader<TRead>
|
where TReader : SerialReader<TValue>
|
||||||
|
where TEvent : SerialEventArgs<TValue>, new()
|
||||||
{
|
{
|
||||||
if (provider.GetRequiredService<TConfiguration>() is TConfiguration configuration)
|
if (provider.GetRequiredService<TConfiguration>() is TConfiguration configuration)
|
||||||
{
|
{
|
||||||
if (cache.TryGetValue(configuration, out ISerialContext? context))
|
if (cache.TryGetValue(configuration, out ISerialContext? context))
|
||||||
{
|
{
|
||||||
return (ISerialContext<TReader, TRead>)context;
|
return (ISerialContext<TReader, TValue, TEvent>)context;
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialPort serialPort = new(configuration.PortName, configuration.BaudRate)
|
SerialPort serialPort = new(configuration.PortName, configuration.BaudRate);
|
||||||
{
|
serialPort.ReadTimeout = 500; // Prevents blocking if no data is available
|
||||||
DtrEnable = true
|
serialPort.WriteTimeout = 500;
|
||||||
};
|
|
||||||
|
|
||||||
SerialConnection connection = new(serialPort);
|
SerialConnection connection = new(serialPort);
|
||||||
SerialStreamer streamer = new(serialPort);
|
SerialStreamer streamer = new(serialPort);
|
||||||
|
|
||||||
context = factory.Create<SerialContext<TReader, TRead>>(connection, streamer);
|
context = factory.Create<SerialContext<TReader, TValue, TEvent>>(connection, streamer);
|
||||||
cache.Add(configuration, context);
|
cache.Add(configuration, context);
|
||||||
|
|
||||||
return (ISerialContext<TReader, TRead>)context;
|
return (ISerialContext<TReader, TValue, TEvent>)context;
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
public record SerialEventArgs<TValue>
|
||||||
|
{
|
||||||
|
public TValue? Value { get; init; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
public record SerialEventArgs(byte Type, short Value);
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using System.Buffers;
|
||||||
|
using System.IO.Pipelines;
|
||||||
|
|
||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
public class SerialEventReader(Stream stream) :
|
||||||
|
SerialReader<SerialEventArgs>(stream)
|
||||||
|
{
|
||||||
|
private readonly PipeReader reader = PipeReader.Create(stream);
|
||||||
|
|
||||||
|
public override async IAsyncEnumerable<SerialEventArgs> ReadAsync()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
ReadResult result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = await reader.ReadAsync();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlySequence<byte> buffer = result.Buffer;
|
||||||
|
|
||||||
|
while (TryParseEvent(ref buffer, out SerialEventArgs serialEvent))
|
||||||
|
{
|
||||||
|
yield return serialEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.AdvanceTo(buffer.Start, buffer.End);
|
||||||
|
|
||||||
|
if (result.IsCompleted)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await reader.CompleteAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryParseEvent(ref ReadOnlySequence<byte> buffer,
|
||||||
|
out SerialEventArgs serialEvent)
|
||||||
|
{
|
||||||
|
SequenceReader<byte> reader = new(buffer);
|
||||||
|
serialEvent = default!;
|
||||||
|
|
||||||
|
if (reader.Remaining < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!reader.TryRead(out byte type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!reader.TryReadLittleEndian(out short value))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
serialEvent = new SerialEventArgs(type, value);
|
||||||
|
|
||||||
|
buffer = buffer.Slice(reader.Position);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public class SerialLineReader(Stream stream) :
|
public class SerialLineReader(Stream stream) :
|
||||||
SerialReader<string>(stream)
|
SerialReader<string>(stream)
|
||||||
{
|
{
|
||||||
private readonly PipeReader reader = PipeReader.Create(stream);
|
private readonly PipeReader reader = PipeReader.Create(stream);
|
||||||
@@ -13,24 +13,31 @@ public class SerialLineReader(Stream stream) :
|
|||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ReadResult result = await reader.ReadAsync();
|
ReadResult result;
|
||||||
ReadOnlySequence<byte> buffer = result.Buffer;
|
try
|
||||||
|
{
|
||||||
|
result = await reader.ReadAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlySequence<byte> buffer = result.Buffer;
|
||||||
while (TryReadLine(ref buffer, out ReadOnlySequence<byte> line))
|
while (TryReadLine(ref buffer, out ReadOnlySequence<byte> line))
|
||||||
{
|
{
|
||||||
yield return EncodingExtensions.GetString(Encoding.UTF8, line);
|
yield return EncodingExtensions.GetString(Encoding.UTF8, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.AdvanceTo(buffer.Start, buffer.End);
|
reader.AdvanceTo(buffer.Start, buffer.End);
|
||||||
if (result.IsCompleted)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (result.IsCompleted)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryReadLine(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> line)
|
private bool TryReadLine(ref ReadOnlySequence<byte> buffer,
|
||||||
|
out ReadOnlySequence<byte> line)
|
||||||
{
|
{
|
||||||
SequencePosition? position = buffer.PositionOf((byte)'\n');
|
SequencePosition? position = buffer.PositionOf((byte)'\n');
|
||||||
if (position == null)
|
if (position == null)
|
||||||
@@ -43,4 +50,4 @@ public class SerialLineReader(Stream stream) :
|
|||||||
buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
|
buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public abstract class SerialReader<TRead>(Stream stream)
|
public abstract class SerialReader<TValue>(Stream stream)
|
||||||
{
|
{
|
||||||
public Stream Stream { get; } = stream;
|
public Stream Stream { get; } = stream;
|
||||||
|
|
||||||
public abstract IAsyncEnumerable<TRead> ReadAsync();
|
public abstract IAsyncEnumerable<TValue> ReadAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public record SerialResponse<TContent> :
|
|
||||||
ISerialResponse
|
|
||||||
{
|
|
||||||
public SerialResponse(ISerialContext context,
|
|
||||||
TContent content)
|
|
||||||
{
|
|
||||||
Context = context;
|
|
||||||
Content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISerialContext Context { get; }
|
|
||||||
|
|
||||||
public TContent Content { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public record SerialResponse
|
|
||||||
{
|
|
||||||
public static SerialResponse<TContent> Create<TContent>(ISerialContext context, TContent content)
|
|
||||||
{
|
|
||||||
return new SerialResponse<TContent>(context, content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,8 +5,5 @@ namespace Toolkit.Foundation;
|
|||||||
public class SerialStreamer(SerialPort serialPort) :
|
public class SerialStreamer(SerialPort serialPort) :
|
||||||
ISerialStreamer
|
ISerialStreamer
|
||||||
{
|
{
|
||||||
public Stream Create()
|
public Stream Create() => serialPort.BaseStream;
|
||||||
{
|
|
||||||
return serialPort.BaseStream;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user