Add Serials
This commit is contained in:
@@ -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="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
<PackageReference Include="Json.More.Net" Version="2.1.1" />
|
<PackageReference Include="Json.More.Net" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.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" />
|
<PackageReference Include="System.Reactive" Version="6.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user