Connection changes

This commit is contained in:
Stoyan Zlatev
2023-12-14 16:18:51 +01:00
parent 0a4476e709
commit 956784294c
35 changed files with 1162 additions and 257 deletions
+157 -4
View File
@@ -2,8 +2,10 @@
using OmniPlus.Hanlers;
using System;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;
namespace OmniPlus
{
@@ -21,6 +23,42 @@ namespace OmniPlus
this.Options.LogFile = $".\\IRDA\\[{portName}].txt";
}
public Byte[] Send(params Byte[] request)
{
this.InvokeLogMessage(">>> PLAIN" + BitConverter.ToString(request));
if (!this.IsOpen)
{
this.OpenII();
}
var response = new Byte[] { };
if (!this.IsOpen || !this.Stream.CanWrite || !this.Stream.CanRead)
{
return response;
}
this.Stream.Write(new byte[] { 1, 1, 1, 1 }, 0, 4);
var asyncState = new IRDAAsyncState
{
Request = request,
Stream = this.Stream
};
var lock_object = new object();
lock (lock_object)
{
Task.Factory.StartNew(asyncState.BeginReadAsync, asyncState.CancellationToken);
asyncState.BeginWriteAsync(request);
}
return asyncState.Response;
}
public byte[] SendMessage(byte[] command)
{
var response = new byte[0];
@@ -76,9 +114,9 @@ namespace OmniPlus
{
var message = default(byte[]);
var length = bytes.Length;
var start = 0;
var start = -1;
while (start < bytes.Length)
while (++start < bytes.Length)
{
if (bytes[start] == OmniPlusExtensions.IRDA_START)
{
@@ -102,11 +140,126 @@ namespace OmniPlus
break;
}
start++;
}
this.MessageReceived?.Invoke(message);
}
}
public class IRDAAsyncState
{
private const int BUFFER_SIZE = 256;
private const int MAX_REPEATS = 5;
private readonly ManualResetEventSlim manualResetEventSlim;
private readonly CancellationTokenSource cancellationTokenSource;
public IRDAAsyncState()
{
this.manualResetEventSlim = new ManualResetEventSlim();
this.cancellationTokenSource = new CancellationTokenSource();
this.CancellationToken = this.cancellationTokenSource.Token;
this.Buffer = new Byte[BUFFER_SIZE];
}
public Int32 Repeats { get; private set; }
public Byte[] Buffer { get; private set; }
public Byte[] Request { get; set; }
public Byte[] Response { get; set; }
public Stream Stream { get; set; }
public CancellationToken CancellationToken { get; }
internal void BeginReadAsync()
{
this.Repeats++;
this.Response = null;
var asyncResult = this.Stream.BeginRead(this.Buffer, 0, this.Buffer.Length, this.EndReadAsync, this);
asyncResult.AsyncWaitHandle.WaitOne();
if (this.Response is null && this.Repeats <= MAX_REPEATS)
{
this.BeginReadAsync();
return;
}
if (this.Response is null)
{
this.Response = new Byte[] { };
}
this.manualResetEventSlim.Set();
}
private void EndReadAsync(IAsyncResult asyncResult)
{
if (asyncResult.AsyncState is IRDAAsyncState asyncState)
{
lock (asyncState)
{
var bytesLength = asyncState.Stream.EndRead(asyncResult);
if (this.Response is null)
{
var response = new Byte[bytesLength];
Array.Copy(this.Buffer, 0, response, 0, bytesLength);
Console.WriteLine("<<< IRDA " + BitConverter.ToString(response));
response = response.FromIrdaMessage();
Console.WriteLine("<<< UI1236 " + BitConverter.ToString(response));
response = response.FromUI1236Message();
Console.WriteLine("<<< OMNI " + BitConverter.ToString(response));
if (response.Length != 0)
{
this.Response = response;
}
}
}
}
}
internal void BeginWriteAsync(Byte[] request)
{
Console.WriteLine(">>> OMNI " + BitConverter.ToString(request));
request = request.ToUI1236Message();
Console.WriteLine(">>> UI1236 " + BitConverter.ToString(request));
request = request.ToIrdaMessage();
Console.WriteLine(">>> IRDA " + BitConverter.ToString(request));
request = request
.ToUI1236Message()
.ToIrdaMessage();
var asyncResult = this.Stream.BeginWrite(request, 0, request.Length, this.EndWriteAsync, this);
asyncResult.AsyncWaitHandle.WaitOne();
this.manualResetEventSlim.Wait();
}
private void EndWriteAsync(IAsyncResult asyncResult)
{
if (asyncResult.AsyncState is IRDAAsyncState asyncState)
{
asyncState.Stream.EndWrite(asyncResult);
}
}
}
}
@@ -5,11 +5,11 @@ using OmniPlus.Options;
using System;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;
namespace OmniPlus
{
internal abstract class SerialPortConnection
internal abstract class SerialPortConnection : IDisposable
{
protected event StateChangedEventHandler StateChanged;
protected event DataReceivedHandler DataReceived;
@@ -17,7 +17,6 @@ namespace OmniPlus
private SerialPort serialPort;
private SerialPortState state;
private bool buisy;
protected SerialPortConnection()
=> this.Options = new SerialPortOptions();
@@ -26,13 +25,66 @@ namespace OmniPlus
public bool Connected => this.state == SerialPortState.Open;
protected bool IsOpen => this.serialPort?.IsOpen ?? false;
protected Stream Stream => this.serialPort.BaseStream;
public virtual void Dispose()
{
try
{
if (this.serialPort != null)
{
this.serialPort.Disposed -= this.Port_Disposed;
this.serialPort.ErrorReceived -= this.Port_ErrorReceived;
this.serialPort.Close();
this.serialPort.Dispose();
this.serialPort = null;
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.WriteLine("... Port disposed");
}
protected virtual void OpenII()
{
this.Dispose();
try
{
this.serialPort = new SerialPort
{
PortName = this.Options.PortName,
BaudRate = (int)this.Options.BaudRate,
DataBits = (int)this.Options.DataBits,
Parity = this.Options.Parity,
StopBits = this.Options.StopBits,
RtsEnable = this.Options.RtsEnabled,
DtrEnable = this.Options.DtrEnabled
};
this.serialPort.Disposed += this.Port_Disposed;
this.serialPort.ErrorReceived += this.Port_ErrorReceived;
this.serialPort.Open();
}
catch (Exception e)
{
}
}
public virtual void Close()
{
try
{
if (this.serialPort != null)
{
// this.serialPort.DataReceived -= this.SerialPort_DataReceived;
this.serialPort.Disposed -= this.SerialPort_Disposed;
this.serialPort.ErrorReceived -= this.SerialPort_ErrorReceived;
this.serialPort.PinChanged -= this.SerialPort_PinChanged;
@@ -86,10 +138,26 @@ namespace OmniPlus
}
}
private void Port_Disposed(Object sender, EventArgs args)
{
this.Dispose();
Console.WriteLine("... Port disposed internal");
}
private void Port_ErrorReceived(Object sender, SerialErrorReceivedEventArgs args)
{
Console.WriteLine("... Port error received");
Console.WriteLine($"... {args.EventType}");
if (!this.serialPort.IsOpen)
{
this.Dispose();
}
}
public virtual void Open()
{
this.Close();
try
{
var fileInfo = new FileInfo(this.Options.LogFile);
@@ -119,8 +187,7 @@ namespace OmniPlus
RtsEnable = this.Options.RtsEnabled,
DtrEnable = this.Options.DtrEnabled
};
// this.serialPort.DataReceived += this.SerialPort_DataReceived;
this.serialPort.Disposed += this.SerialPort_Disposed;
this.serialPort.ErrorReceived += this.SerialPort_ErrorReceived;
this.serialPort.PinChanged += this.SerialPort_PinChanged;
@@ -136,7 +203,7 @@ namespace OmniPlus
+ $", {this.Options.BaudRate}"
+ $", {this.Options.DataBits}"
+ $", {this.Options.Parity}"
+ $", {this.Options.StopBits}");
+ $", {this.Options.StopBits}");
}
catch (Exception e)
{
@@ -231,12 +298,13 @@ namespace OmniPlus
private bool BeginWaitingResponseAsync()
{
var buffer = new byte[1024];
var baseStream = this.serialPort.BaseStream;
this.serialPort?.BaseStream?.BeginRead(buffer, 0, buffer.Length, delegate(IAsyncResult asyncResult)
var ar = baseStream.BeginRead(buffer, 0, buffer.Length, delegate(IAsyncResult asyncResult)
{
try
{
var actualLength = this.serialPort?.BaseStream?.EndRead(asyncResult) ?? 0;
var actualLength = baseStream.EndRead(asyncResult);
if (actualLength <= 0)
{
@@ -257,6 +325,8 @@ namespace OmniPlus
}
}, null);
Task.Factory.StartNew(ar.AsyncWaitHandle.WaitOne);
return this.serialPort != null && this.serialPort.IsOpen;
}
}
@@ -4,8 +4,6 @@ namespace OmniPlus.Features
{
public class FeatureRequest : FeatureResponse
{
protected readonly int length;
public FeatureRequest(int length)
: base(length)
=> this.length = length;
+17 -11
View File
@@ -6,21 +6,30 @@ namespace OmniPlus.Features
{
public class FeatureResponse
{
protected int length;
protected readonly byte[] bytes;
public FeatureResponse(int length = 0)
=> this.bytes = new byte[length];
public FeatureResponse(int length = 0)
{
this.length = length;
this.bytes = new byte[length];
}
public FeatureResponse(byte[] response, int length = 0) : this(length)
{
if (response?.Length > 0)
if (response != null)
{
this.Status = (Status)response[0];
}
var responseLength = response.Length;
if (response?.Length > length)
{
Array.Copy(response, 1, this.bytes, 0, length);
if (responseLength > 0)
{
this.Status = (Status)response[0];
}
if (responseLength > this.length)
{
Array.Copy(response, 1, this.bytes, 0, this.length);
}
}
}
@@ -36,8 +45,5 @@ namespace OmniPlus.Features
public override string ToString()
=> BitConverter.ToString(this.bytes);
//public static implicit operator byte[](FeatureResponse response)
// => response?.bytes ?? new byte[0];
}
}
+84
View File
@@ -0,0 +1,84 @@
namespace OmniPlus
{
using System;
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Linq;
public class OMNIPool
{
private readonly ConcurrentDictionary<OMNISlot, OMNIFeatures> features;
private readonly ConcurrentDictionary<OMNISlot, OMNIConnection> connections;
public OMNIPool()
{
this.connections = new ConcurrentDictionary<OMNISlot, OMNIConnection>();
}
public void AddConnection(String portNr)
{
var slot = new OMNISlot(this.connections.Count + 1, portNr);
_ = this.features.AddOrUpdate(slot, new OMNIFeatures(), (_slot, _) => new OMNIFeatures());
_ = this.connections.AddOrUpdate(slot, new OMNIConnection(slot), (_slot, _) => new OMNIConnection(_slot));
}
}
public class OMNIConnection
{
private readonly OMNISlot slot;
private readonly OMNIFeatures features;
public OMNIConnection(OMNISlot slot)
{
this.slot = slot;
this.features = new OMNIFeatures();
}
}
public class OMNIFeatures
{
}
public class OMNISlot : IComparable<OMNISlot>
{
public OMNISlot(Int32 nr, String port)
{
if (string.IsNullOrWhiteSpace(port))
{
throw new ArgumentNullException("COM port is required!");
}
else if (!SerialPort.GetPortNames().Any(x => x == port))
{
throw new ArgumentException("COM port dose not exists!");
}
this.Nr = nr;
this.Port = port;
}
public Int32 Nr { get; }
public String Port { get; }
public Int32 CompareTo(OMNISlot other)
{
return this.Port.CompareTo(other.Port);
}
public override Boolean Equals(Object other)
{
return this.Equals(other);
}
public override Int32 GetHashCode()
{
return this.Port.GetHashCode();
}
public override String ToString()
{
return $"{this.Nr}. {this.Port}";
}
}
}
+5
View File
@@ -34,6 +34,9 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.6.0.4\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@@ -100,6 +103,7 @@
<Compile Include="OmniPlusMeter.cs" />
<Compile Include="OmniPlusStateChanged.cs" />
<Compile Include="OmniPlusType.cs" />
<Compile Include="OMNIPool.cs" />
<Compile Include="Options\OmniControlOptions.cs" />
<Compile Include="Options\SerialPortOptions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -110,6 +114,7 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ExchangeHub\ExchangeHub.csproj">
+1 -9
View File
@@ -30,7 +30,7 @@ namespace OmniPlus
this.irdaConnection.Open();
this.connected = () => this.irdaConnection.Connected;
this.MessageHandler = this.irdaConnection.SendMessage;
this.MessageHandler = this.irdaConnection.Send;
return this.irdaConnection.Connected;
}
@@ -412,13 +412,5 @@ namespace OmniPlus
return new FeatureResponse();
}
private void WaitBeforeNextExecution()
{
while (this.secondsToWait > 0)
{
this.secondsToWait--;
}
}
}
}
+10
View File
@@ -202,6 +202,16 @@ namespace OmniPlus
return payload;
}
var bytesLength = bytes.Length;
if (bytesLength >= 2)
{
if (bytes[1] == IRDA_PING)
{
return payload;
}
}
var payloadLength = bytes.Length - IRDA_MIN_LENGTH;
if (payloadLength <= OxOO)
+6 -4
View File
@@ -14,12 +14,14 @@
{
get
{
if (this.MeterVolume != 0 && this.VolumeMessured != 0)
try
{
return this.MeterVolume / this.VolumeMessured * 100;
return 100 - this.MeterVolume / this.VolumeMessured * 100;
}
catch
{
return -1;
}
return 0;
}
}
}
+3
View File
@@ -29,5 +29,8 @@ namespace OmniPlus
return seconds * milliliter / 1000 / 1000;
}
public double VolumeM3(OmniPlusTest test)
=> this.VolumeM3(test.Rotations, test.Duration);
}
}
@@ -1,5 +1,8 @@
using OmniPlus.Enums;
using Newtonsoft.Json;
using System;
using System.IO.Ports;
namespace OmniPlus.Options
@@ -32,5 +35,8 @@ namespace OmniPlus.Options
public bool DtrEnabled { get; set; }
public string LogFile { get; set; }
public override String ToString()
=> JsonConvert.SerializeObject(this, Formatting.Indented);
}
}
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net40" />
</packages>