Files
laatzen/Common/OmniPlus/OmniPlusConnectionsPool.cs
T
2023-11-09 10:34:37 +01:00

352 lines
13 KiB
C#

//using OmniPipes;
using OmniPlus.Connections;
using OmniPlus.Features;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Threading.Tasks;
using static OmniPlus.UI.Inspection.OmniPlusInspectionHeaders;
namespace OmniPlus.UI.Inspection
{
public class OmniPlusConnectionsPool : IDisposable
{
public event OmniPlusStateChangedEventHandler StateChanged;
private readonly ConcurrentDictionary<int, OmniPlusConnection> connections;
private readonly ConcurrentDictionary<int, OmniPlusMeter> meters;
private readonly ConcurrentDictionary<int, Task> tasks;
//private readonly NamedPipeClient namedPipeClient;
private readonly OmniPlusDatabase database;
private bool available;
private int size;
public OmniPlusConnectionsPool(string dbConnectionString)
{
this.connections = new ConcurrentDictionary<int, OmniPlusConnection>();
this.meters = new ConcurrentDictionary<int, OmniPlusMeter>();
//this.namedPipeClient = new NamedPipeClient();
this.database = new OmniPlusDatabase(dbConnectionString);
}
public void Dispose()
{
if (this.StateChanged != null)
{
foreach (var callback in this.StateChanged.GetInvocationList())
{
if (callback is OmniPlusStateChangedEventHandler stateChangedCallback)
{
this.StateChanged -= stateChangedCallback;
}
}
}
foreach (var connection in this.connections.Values)
{
connection?.Disconnect();
}
//this.namedPipeClient.Connected -= this.NamedPipeClient_Connected;
//this.namedPipeClient.Disconnected -= this.NamedPipeClient_Disconnected;
//this.namedPipeClient.Disconnect();
this.connections.Clear();
this.meters.Clear();
}
public void InitializeInspection(params string[] portNames)
{
//this.namedPipeClient.Connected += this.NamedPipeClient_Connected;
//this.namedPipeClient.Disconnected += this.NamedPipeClient_Disconnected;
//this.namedPipeClient.Connect();
OmniPlusConnection connection;
OmniPlusMeter meter;
var connections = 0;
var position = 1;
foreach (var portName in portNames)
{
connection = new OmniPlusConnection(portName);
meter = new OmniPlusMeter();
if (connection.ConnectIrda())
{
meter.Connected = true;
connections++;
}
else
{
connection.Disconnect();
connection = default(OmniPlusConnection);
meter = default(OmniPlusMeter);
}
this.meters.TryAdd(position, meter);
this.connections.TryAdd(position, connection);
this.StateChanged?.Invoke(position, true, SLOT_NR, position.ToString());
position++;
}
if (this.available)
{
this.available = connections > 0;
}
}
public void StartInspection()
{
this.StartOmniInitialization();
this.StartOmniCalibration();
this.FinishOmniInspection();
}
private void StartOmniInitialization()
{
var factory = Task.Factory;
foreach (var position in this.connections.Keys)
{
this.tasks[position] = factory.StartNew(() => this.StartOmniInitialization(position));
}
factory.ContinueWhenAll(this.tasks.Values.ToArray(), _ => { });
}
private void StartOmniInitialization(int position)
{
if (this.TryGetOmni(position, out var connection, out var meter))
{
this.StateChanged?.Invoke(position, meter.Connected, CONNECTED, meter.Connected ? OK : X);
var systemParameters = connection.ViewSystemParameters();
meter.Initialized = systemParameters.Succeeded;
meter.AddSystemParameters(systemParameters);
this.database.AddOrUpdate(systemParameters);
this.StateChanged?.Invoke(position, meter.FirmwareInRange, FIRMWARE, meter.Firmware);
this.StateChanged?.Invoke(position, true, BUILD_INFO, meter.BuildInfo);
this.StateChanged?.Invoke(position, meter.ManifacturingTimeInRange, CREATED_ON, $"{meter.ManifacturingTime:yyyy-MM-dd}");
this.StateChanged?.Invoke(position, meter.SystemTimeInRange, LAST_UPDATE, $"{meter.SystemTimeDrift} Sek.");
this.StateChanged?.Invoke(position, meter.RebootsCount != 0xFF, REBOOTS_CNT, meter.RebootsCount.ToString());
this.StateChanged?.Invoke(position, !meter.FactorySealed, SEALED, !meter.FactorySealed ? X : OK);
if (meter.Initialized)
{
var inputVolume = this.database.GetInputVolume(meter.Size);
var inputVolumResponse = connection.SetInputVolume(inputVolume);
meter.Initialized = inputVolumResponse.Succeeded;
if (meter.Initialized)
{
meter.AddInputVolume(inputVolume);
}
}
this.StateChanged?.Invoke(position, meter.Initialized, ML_PER_PULSE, $"{meter.MlPerPulse:0.00000}");
}
else // meter or connection not in use
{
this.StateChanged?.Invoke(position, null, CONNECTED, null);
this.StateChanged?.Invoke(position, null, FIRMWARE, null);
this.StateChanged?.Invoke(position, null, BUILD_INFO, null);
this.StateChanged?.Invoke(position, null, CREATED_ON, null);
this.StateChanged?.Invoke(position, null, LAST_UPDATE, null);
this.StateChanged?.Invoke(position, null, REBOOTS_CNT, null);
this.StateChanged?.Invoke(position, null, SEALED, null);
this.StateChanged?.Invoke(position, null, ML_PER_PULSE, null);
}
}
private void StartOmniCalibration()
{
var factory = Task.Factory;
var inspectionPoints = this.database.GetInspectionPoints(this.size);
foreach (var point in inspectionPoints)
{
//this.namedPipeClient.RequestFlowRate(point.FlowRate);
foreach (var position in this.connections.Keys)
{
this.tasks[position] = factory.StartNew(() => this.StartOmniCalibration(position, point));
}
factory.ContinueWhenAll(this.tasks.Values.ToArray(), _ => { });
//var volume = this.namedPipeClient.RequestReference();
//foreach (var meter in this.meters.Values)
//{
// meter.AddInspectionVolume(point, volume);
//}
}
foreach(var position in this.connections.Keys)
{
this.tasks[position] = factory.StartNew(() => this.CalibrateMeter(position));
}
factory.ContinueWhenAll(this.tasks.Values.ToArray(), _ => { });
}
private void StartOmniCalibration(int position, OmniPlusInspectionPoint point)
{
var header = $"{point.Rotations}/{point.Seconds}R/Sek.";
var progress = 0;
this.StateChanged?.Invoke(position, null, header, $"{progress}%");
if (this.TryGetOmni(position, out var connection, out var meter))
{
if (!meter.CanCalibrate)
{
this.StateChanged?.Invoke(position, false, header, X);
return;
}
var activationResponse = connection.StartChamberCalibration(point.Rotations, point.Seconds);
var calibrationResult = default(ChamberCalibration);
if (activationResponse.Succeeded)
{
progress += 10;
this.StateChanged?.Invoke(position, true, header, $"{progress}%");
//0x00 indicates that the parameters are valid and test will start 3 seconds after the response.
Thread.Sleep(3000);
progress += 10;
this.StateChanged?.Invoke(position, true, header, $"{progress}%");
// waiting all the secconds to execute test
Thread.Sleep(point.Seconds * 1000);
progress += 70;
this.StateChanged?.Invoke(position, true, header, $"{progress}%");
var delay = (int)(point.Seconds * 0.1) * 1000;
for (int i = 0; i < 3; i++)
{
calibrationResult = connection.ViewChamberCalibration();
if (calibrationResult.Succeeded)
{
break;
}
Thread.Sleep(delay);
progress += 3;
this.StateChanged?.Invoke(position, true, header, $"{progress}%");
}
if (calibrationResult?.Succeeded == true)
{
if (calibrationResult.Control == ChamberCalibration.TEST_COMPLETED)
{
this.StateChanged?.Invoke(position, true, header, $"100%");
}
else // calibration timeout or not ready but exceeds the 3s + seconds to run + 0.3%
{
this.StateChanged?.Invoke(position, false, header, X);
}
}
else // calibration failed
{
this.StateChanged?.Invoke(position, false, header, "n/a");
}
}
else // activation failed
{
this.StateChanged?.Invoke(position, false, header, "n/a");
}
meter.AddCalibrationResult(point, calibrationResult);
}
else // meter or connection not in use
{
this.StateChanged?.Invoke(position, null, header, null);
}
}
private void CalibrateMeter(int position)
{
if (this.TryGetOmni(position, out var connection, out var meter))
{
var correctionFactor = meter.CalculateCorrectionFactor();
this.StateChanged?.Invoke(position, meter.Calibrated, CORRECTION, $"{correctionFactor:0.00}%");
}
else // meter or connection not in use
{
this.StateChanged?.Invoke(position, null, CORRECTION, null);
}
}
private void FinishOmniInspection()
{
var factory = Task.Factory;
foreach (var position in this.connections.Keys)
{
this.tasks[position] = factory.StartNew(() => this.FinishOmniInspection(position));
}
}
private void FinishOmniInspection(int position)
{
if (this.TryGetOmni(position, out var connection, out var meter))
{
var configurationParameters = connection.ViewConfigurationParameters();
var canContinue = configurationParameters.Succeeded;
if (canContinue)
{
var systemTimeReset = connection.SetSystemTime();
canContinue = systemTimeReset.Succeeded;
}
//if (canContinue)
//{
// var registerSettings = connection.ViewRegisterSettings();
//}
}
else // meter or connection not in use
{
}
}
private bool TryGetOmni(int position, out OmniPlusConnection connection, out OmniPlusMeter meter)
{
var connectionFound = this.connections.TryGetValue(position, out connection);
var meterFound = this.meters.TryGetValue(position, out meter);
return connectionFound
&& connection != null
&& meterFound
&& meter != null
&& meter.Connected;
}
private void NamedPipeClient_Connected()
=> this.available = true;
private void NamedPipeClient_Disconnected()
=> this.available = false;
}
}