You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
4.4 KiB
133 lines
4.4 KiB
using Common.Logging;
|
|
using CommunityToolkit.Mvvm.Messaging;
|
|
using MultiTerm.Protocols.Model;
|
|
using MultiTerm.Protocols.Types;
|
|
using RJCP.IO.Ports;
|
|
using System.Text;
|
|
|
|
namespace MultiTerm.Protocols.Serial;
|
|
|
|
public class SerialProtocol : CommunicationProtocol
|
|
{
|
|
public override ProtocolType ProtocolType => ProtocolType.Serial;
|
|
|
|
public override string InstanceIdentifier { get; protected set; } = string.Empty;
|
|
public override string LongInstanceIdentifier { get; protected set; } = string.Empty;
|
|
|
|
private ISerialProtocolSettings? serialSettings;
|
|
private SerialPortStream serialPort = new();
|
|
|
|
|
|
public SerialProtocol(ILogger logger, IMessenger messenger) : base(logger, messenger) { }
|
|
|
|
protected override bool InternalConnect(IProtocolSettings settings)
|
|
{
|
|
// check if settings are of correct type
|
|
if (settings is not ISerialProtocolSettings serialProtocolSettings)
|
|
{
|
|
this.serialSettings = null;
|
|
throw new ArgumentException($"Cannot connect due to wrong type of Protocol Settings. " +
|
|
$"Check parameter {nameof(settings)}' of '{nameof(InternalConnect)}()' in {nameof(SerialProtocol)}.");
|
|
}
|
|
|
|
// store locally
|
|
this.serialSettings = serialProtocolSettings;
|
|
|
|
// update identifier
|
|
this.InstanceIdentifier = this.serialSettings.PortName;
|
|
this.LongInstanceIdentifier = this.serialSettings.PortName;
|
|
|
|
// create new serial port
|
|
this.serialPort = new()
|
|
{
|
|
// apply user settings, where needed converters are used
|
|
PortName = this.serialSettings.PortName,
|
|
BaudRate = this.serialSettings.BaudRate,
|
|
DataBits = this.serialSettings.DataBits,
|
|
Parity = new ParityLibraryEquivalentConverter().ConvertToLibraryType(this.serialSettings.Parity),
|
|
StopBits = new StopBitsLibraryEquivalentConverter().ConvertToLibraryType(this.serialSettings.StopBits),
|
|
Handshake = new HandshakeLibraryEquivalentConverter().ConvertToLibraryType(this.serialSettings.Handshake),
|
|
|
|
// define static settings
|
|
Encoding = Encoding.ASCII,
|
|
ReadTimeout = 500,
|
|
WriteTimeout = 500
|
|
};
|
|
|
|
// try opening serial port
|
|
try
|
|
{
|
|
this.serialPort.Open();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
this.logger.LogException(ex, $"'{nameof(InternalConnect)}()'Opening serial port failed:", nameof(SerialProtocol));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
protected override void InternalDisconnect()
|
|
{
|
|
this.serialPort.Close();
|
|
this.serialSettings = null;
|
|
}
|
|
|
|
protected override void InternalRead(CancellationToken ct)
|
|
{
|
|
while(ct.IsCancellationRequested == false)
|
|
{
|
|
int readByte = -1;
|
|
|
|
// try reading
|
|
try
|
|
{
|
|
// reads character based on configured encoding (here ASCII)
|
|
readByte = this.serialPort.ReadByte();
|
|
}
|
|
catch (IOException ex) // thrown when a device disconnected
|
|
{
|
|
this.logger.LogException(ex, $"Exception while reading data in {nameof(InternalRead)}", nameof(SerialProtocol));
|
|
this.OnUnintentionallyDisconnected(); // report disconnect
|
|
break; // break loop
|
|
}
|
|
|
|
if (readByte != -1) // -1 = end of stream
|
|
{
|
|
// report new data with event
|
|
this.OnReceivedData(new ExtendedByte((byte)readByte));
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override bool InternalSendBytes(byte[] bytes)
|
|
{
|
|
foreach (byte b in bytes)
|
|
{
|
|
try
|
|
{
|
|
this.serialPort.WriteByte(b);
|
|
}
|
|
// When the Serial Port is closed and InvalidOperationException is thrown => report error
|
|
catch(InvalidOperationException)
|
|
{
|
|
this.OnUnintentionallyDisconnected();
|
|
return false;
|
|
}
|
|
// any other exception => report error
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// report that data was be sent
|
|
this.OnSentData(new ExtendedByte(b));
|
|
}
|
|
return true; // success
|
|
}
|
|
|
|
public static IEnumerable<string> GetPortNames()
|
|
{
|
|
return SerialPortStream.GetPortNames();
|
|
}
|
|
}
|
|
|