|
|
|
@ -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<ReceivedDataEventArgs>? ReceivedDataEvent; |
|
|
|
|
|
|
|
public event EventHandler<SentDataEventArgs>? 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; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// To be called when data was received from the connected device. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
/// <param name="e"><see cref="ReceivedDataEventArgs"/></param> |
|
|
|
|
|
|
|
protected void OnReceivedData(ReceivedDataEventArgs e) { this.ReceivedDataEvent?.Invoke(this, e); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// To be called when data was sent to the connected device. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
/// <param name="e"><see cref="SentDataEventArgs"/></param> |
|
|
|
|
|
|
|
protected void OnSentData(SentDataEventArgs e) { this.SentDataEvent?.Invoke(this, e); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// Allows to send bytes using the implemented protocol. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
/// <param name="bytes">data as bytes</param> |
|
|
|
|
|
|
|
protected abstract void InternalSendBytes(byte[] bytes); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void SendBytes(byte[] bytes) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
this.InternalSendBytes(bytes); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// Allows to connect to the selected device using the implemented protocol. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
/// <returns>true on success</returns> |
|
|
|
|
|
|
|
protected abstract bool InternalConnect(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// Reads from the connected device in an endless loop. |
|
|
|
|
|
|
|
/// The endless loop must be ended when the <paramref name="ct"/> has <see cref="CancellationToken.IsCancellationRequested"/> set. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
/// <param name="ct">cancellation token</param> |
|
|
|
|
|
|
|
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)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// Allows to disconnect from the connected device. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
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(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |