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; private ISerialProtocolSettings? serialSettings; private SerialPortStream serialPort = new(); public SerialProtocol(ILogger logger, IMessenger messenger) : base(logger, messenger) { } protected override bool InternalConnect(IProtocolSettings protocolSettings) { // check if settings are of correct type if (protocolSettings is not ISerialProtocolSettings serialProtocolSettings) { this.serialSettings = null; throw new ArgumentException($"Cannot connect due to wrong type of Protocol Settings. " + $"Check parameter {nameof(protocolSettings)}' of '{nameof(InternalConnect)}()' in {nameof(SerialProtocol)}."); } // store locally this.serialSettings = serialProtocolSettings; // update identifier this.InstanceIdentifier = 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 { 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() { serialPort.Close(); this.serialSettings = null; } protected override void InternalRead(CancellationToken ct) { while(ct.IsCancellationRequested == false) { // reads character based on configured encoding (here ASCII) int readCharacter = serialPort.ReadChar(); if (readCharacter != -1) // -1 = timeout { // create extended char type var character = new ExtendedChar((char)readCharacter); // report new data with event this.OnReceivedData(new ReceivedDataEventArgs(new ExtendedChar[] { character })); } } } protected override bool InternalSendBytes(byte[] bytes) { foreach (byte b in bytes) { try { serialPort.WriteByte(b); } // When the Serial Port is closed and InvalidOperationException is thrown catch(InvalidOperationException) { this.OnUnintentionallyDisconnected(); } } return true; } public static IEnumerable GetPortNames() { return SerialPortStream.GetPortNames(); } }