From b05f3ff13748b86de2f9c5141b4d23b3e8af1994 Mon Sep 17 00:00:00 2001 From: Jonas Arnold Date: Mon, 10 Apr 2023 11:32:57 +0200 Subject: [PATCH] implemented abstract CommunicationProtocol and enhanced ICommunicationProtocol --- MultiTerm.Protocols/CommunicationProtocol.cs | 96 +++++++++++++++++++ MultiTerm.Protocols/ICommunicationProtocol.cs | 43 +++++++++ .../MultiTerm.Protocols.csproj | 4 + MultiTerm.Protocols/ReceivedDataEventArgs.cs | 13 +++ MultiTerm.Protocols/SentDataEventArgs.cs | 13 +++ 5 files changed, 169 insertions(+) create mode 100644 MultiTerm.Protocols/CommunicationProtocol.cs create mode 100644 MultiTerm.Protocols/ICommunicationProtocol.cs create mode 100644 MultiTerm.Protocols/ReceivedDataEventArgs.cs create mode 100644 MultiTerm.Protocols/SentDataEventArgs.cs diff --git a/MultiTerm.Protocols/CommunicationProtocol.cs b/MultiTerm.Protocols/CommunicationProtocol.cs new file mode 100644 index 0000000..14aab03 --- /dev/null +++ b/MultiTerm.Protocols/CommunicationProtocol.cs @@ -0,0 +1,96 @@ +using Common.Logging; + +namespace MultiTerm.Protocols; + +public abstract class CommunicationProtocol : ICommunicationProtocol +{ + public string NewlineSequenceOnSend { get; set; } + + public string NewlineOnReceivedSequence { get; set; } + + protected ILogger logger; + private CancellationTokenSource cancellationTokenSource; + private Thread? readingThread; + + public event EventHandler? ReceivedDataEvent; + public event EventHandler? SentDataEvent; + + + public CommunicationProtocol(ILogger logger) + { + // initialize with empty string, must be correctly initalized by factory + this.NewlineSequenceOnSend = string.Empty; + this.NewlineOnReceivedSequence = string.Empty; + + // initialize other + this.cancellationTokenSource = new CancellationTokenSource(); + this.logger = logger; + } + + /// + /// To be called when data was received from the connected device. + /// + /// + protected void OnReceivedData(ReceivedDataEventArgs e) { this.ReceivedDataEvent?.Invoke(this, e); } + + /// + /// To be called when data was sent to the connected device. + /// + /// + protected void OnSentData(SentDataEventArgs e) { this.SentDataEvent?.Invoke(this, e); } + + /// + /// Allows to send bytes using the implemented protocol. + /// + /// data as bytes + protected abstract void InternalSendBytes(byte[] bytes); + + public void SendBytes(byte[] bytes) + { + this.InternalSendBytes(bytes); + } + + /// + /// Allows to connect to the selected device using the implemented protocol. + /// + /// true on success + protected abstract bool InternalConnect(); + + /// + /// Reads from the connected device in an endless loop. + /// The endless loop must be ended when the has set. + /// + /// cancellation token + protected abstract void InternalRead(CancellationToken ct); + + public void Connect() + { + if (this.InternalConnect()) + { + // renew token source + this.cancellationTokenSource = new CancellationTokenSource(); + // start internal reading thread + this.readingThread = new Thread(() => this.InternalRead(this.cancellationTokenSource.Token)); + this.readingThread.Start(); + } + else + { + this.logger.LogWarn($"'{nameof(Connect)}()' failed to connect to protocol, did not start reading thread.", nameof(CommunicationProtocol)); + } + } + + /// + /// Allows to disconnect from the connected device. + /// + protected abstract void InternalDisconnect(); + public void Disconnect() + { + // if reading thread exists and is running => cancel it and wait + if (this.readingThread != null && this.readingThread.IsAlive) + { + this.cancellationTokenSource.Cancel(); + this.readingThread.Join(); + } + this.InternalDisconnect(); + } +} diff --git a/MultiTerm.Protocols/ICommunicationProtocol.cs b/MultiTerm.Protocols/ICommunicationProtocol.cs new file mode 100644 index 0000000..cd02870 --- /dev/null +++ b/MultiTerm.Protocols/ICommunicationProtocol.cs @@ -0,0 +1,43 @@ +namespace MultiTerm.Protocols; + +/// +/// Interface to interact with a Communication protocol. +/// +public interface ICommunicationProtocol +{ + /// + /// Newline sequence to add on the end when sending a message using . + /// + string NewlineSequenceOnSend { get; } + + /// + /// When this sequence is detected while reading, a new line is introduced. + /// + string NewlineOnReceivedSequence { get; } + + /// + /// New data received from connected device. + /// + event EventHandler? ReceivedDataEvent; + + /// + /// New data sent to the connected device. + /// + event EventHandler? SentDataEvent; + + /// + /// Connect to the device. + /// + void Connect(); + + /// + /// Disconnect from the device. Ends all internal activities. + /// + void Disconnect(); + + /// + /// Send data to the connected device. + /// + /// data to send, as an array of bytes + void SendBytes(byte[] bytes); +} diff --git a/MultiTerm.Protocols/MultiTerm.Protocols.csproj b/MultiTerm.Protocols/MultiTerm.Protocols.csproj index 132c02c..56e7d3b 100644 --- a/MultiTerm.Protocols/MultiTerm.Protocols.csproj +++ b/MultiTerm.Protocols/MultiTerm.Protocols.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/MultiTerm.Protocols/ReceivedDataEventArgs.cs b/MultiTerm.Protocols/ReceivedDataEventArgs.cs new file mode 100644 index 0000000..856185b --- /dev/null +++ b/MultiTerm.Protocols/ReceivedDataEventArgs.cs @@ -0,0 +1,13 @@ +using MultiTerm.Protocols.Model; + +namespace MultiTerm.Protocols; + +public class ReceivedDataEventArgs : EventArgs +{ + public IEnumerable ReceivedCharacters { get; private set; } + + public ReceivedDataEventArgs(IEnumerable receivedCharacters) + { + this.ReceivedCharacters = receivedCharacters; + } +} diff --git a/MultiTerm.Protocols/SentDataEventArgs.cs b/MultiTerm.Protocols/SentDataEventArgs.cs new file mode 100644 index 0000000..ffa3c77 --- /dev/null +++ b/MultiTerm.Protocols/SentDataEventArgs.cs @@ -0,0 +1,13 @@ +using MultiTerm.Protocols.Model; + +namespace MultiTerm.Protocols; + +public class SentDataEventArgs : EventArgs +{ + public IEnumerable SentCharacters { get; private set; } + + public SentDataEventArgs(IEnumerable sentCharacters) + { + this.SentCharacters = sentCharacters; + } +} \ No newline at end of file