Add Serials
This commit is contained in:
@@ -4,4 +4,4 @@ public class ActionableInitializationScoped(IServiceProvider provider,
|
||||
Action<IServiceProvider> delegateAction) : IInitializationScoped
|
||||
{
|
||||
public void Initialize() => delegateAction.Invoke(provider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface ISerialConfiguration
|
||||
{
|
||||
public string PortName { get; set; }
|
||||
|
||||
public int BaudRate { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface ISerialConnection
|
||||
{
|
||||
bool IsOpen { get; }
|
||||
|
||||
void Close();
|
||||
|
||||
bool Open();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface ISerialConnectionStreamer
|
||||
{
|
||||
Stream Stream { get; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface ISerialContext<TSerialReader, TContent> :
|
||||
ISerialContext where TSerialReader : SerialReader<TContent>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface ISerialContext
|
||||
{
|
||||
void Open();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface ISerialFactory
|
||||
{
|
||||
ISerialContext<TSerialReader, TContent> Create<TSerialReader, TContent>(ISerialConfiguration configuration)
|
||||
where TSerialReader : SerialReader<TContent>;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface ISerialResponse
|
||||
{
|
||||
ISerialContext Context { get; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface ISerialStreamer
|
||||
{
|
||||
Stream Create();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface ISerialWriter
|
||||
{
|
||||
void Write(byte[] buffer, int offset, int count);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class SerialConfiguration :
|
||||
ISerialConfiguration
|
||||
{
|
||||
[NotNull]
|
||||
public string? PortName { get; set; }
|
||||
|
||||
public int BaudRate { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class SerialConnection(SerialPort serialPort) :
|
||||
ISerialConnection
|
||||
{
|
||||
public bool IsOpen { get; private set; }
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (IsOpen)
|
||||
{
|
||||
try
|
||||
{
|
||||
serialPort.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
IsOpen = serialPort.IsOpen;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Open()
|
||||
{
|
||||
if (!IsOpen)
|
||||
{
|
||||
try
|
||||
{
|
||||
serialPort.Open();
|
||||
|
||||
serialPort.DiscardInBuffer();
|
||||
serialPort.DiscardOutBuffer();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
IsOpen = serialPort.IsOpen;
|
||||
}
|
||||
|
||||
return IsOpen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class SerialContext<TSerialReader, TContent>(IMessenger messenger,
|
||||
ISerialConnection connection,
|
||||
ISerialStreamer serialStreamer) :
|
||||
ISerialContext<TSerialReader, TContent> where TSerialReader : SerialReader<TContent>
|
||||
{
|
||||
public async void Open()
|
||||
{
|
||||
if (connection.Open())
|
||||
{
|
||||
Stream stream = serialStreamer.Create();
|
||||
|
||||
if ((TSerialReader?)Activator.CreateInstance(typeof(TSerialReader), [stream]) is TSerialReader reader)
|
||||
{
|
||||
await foreach (TContent content in reader.ReadAsync())
|
||||
{
|
||||
messenger.Send(SerialResponse.Create(this, content));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class SerialFactory(IServiceFactory factory) :
|
||||
ISerialFactory
|
||||
{
|
||||
private readonly Dictionary<ISerialConfiguration, ISerialContext> cache = [];
|
||||
|
||||
public ISerialContext<TSerialReader, TContent> Create<TSerialReader, TContent>(ISerialConfiguration configuration)
|
||||
where TSerialReader : SerialReader<TContent>
|
||||
{
|
||||
if (cache.TryGetValue(configuration, out ISerialContext? context))
|
||||
{
|
||||
return (ISerialContext<TSerialReader, TContent>)context;
|
||||
}
|
||||
|
||||
SerialPort serialPort = new(configuration.PortName, configuration.BaudRate)
|
||||
{
|
||||
DtrEnable = true
|
||||
};
|
||||
|
||||
SerialConnection connection = new(serialPort);
|
||||
SerialStreamer streamer = new(serialPort);
|
||||
|
||||
context = factory.Create<SerialContext<TSerialReader, TContent>>(connection, streamer);
|
||||
cache.Add(configuration, context);
|
||||
|
||||
return (ISerialContext<TSerialReader, TContent>)context;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.Buffers;
|
||||
using System.IO.Pipelines;
|
||||
using System.Text;
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class SerialLineReader(Stream stream) :
|
||||
SerialReader<string>(stream)
|
||||
{
|
||||
private readonly PipeReader reader = PipeReader.Create(stream);
|
||||
|
||||
public override async IAsyncEnumerable<string> ReadAsync()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
ReadResult result = await reader.ReadAsync();
|
||||
ReadOnlySequence<byte> buffer = result.Buffer;
|
||||
|
||||
while (TryReadLine(ref buffer, out ReadOnlySequence<byte> line))
|
||||
{
|
||||
yield return EncodingExtensions.GetString(Encoding.UTF8, line);
|
||||
}
|
||||
|
||||
reader.AdvanceTo(buffer.Start, buffer.End);
|
||||
if (result.IsCompleted)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool TryReadLine(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> line)
|
||||
{
|
||||
SequencePosition? position = buffer.PositionOf((byte)'\n');
|
||||
if (position == null)
|
||||
{
|
||||
line = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
line = buffer.Slice(0, position.Value);
|
||||
buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public abstract class SerialReader<TContent>(Stream stream)
|
||||
{
|
||||
public Stream Stream { get; } = stream;
|
||||
|
||||
public abstract IAsyncEnumerable<TContent> ReadAsync();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class SerialStreamer(SerialPort serialPort) :
|
||||
ISerialStreamer
|
||||
{
|
||||
public Stream Create()
|
||||
{
|
||||
return serialPort.BaseStream;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Json.More.Net" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.1" />
|
||||
<PackageReference Include="System.IO.Ports" Version="9.0.1" />
|
||||
<PackageReference Include="System.Reactive" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user