common/CordonelPreadjustmentUi/Processes/Actions/OffsetTestProcess.cs
2026-04-23 17:50:07 +02:00

299 lines
16 KiB
C#

using CordonelPreadjustmentUi.Helper;
using CordonelPreadjustmentUi.Processes.Itinerary;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.MeasurementRecords;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Ui.CordonelPreadjustmentUi.Helper.Extensions;
using static CordonelPreadjustmentUi.PreAdjustmentControl;
namespace CordonelPreadjustmentUi.Processes.Actions
{
public class OffsetTestProcess : BaseProcess
{
public OffsetTestProcess(string processName, StatusPanelItems panelState, string performMessage, string failedMessage, int? expectedTimeS) : base(processName, panelState, performMessage, failedMessage, expectedTimeS)
{
}
public override List<Task> StartWork()
{
return doWorkProcess(base.CurrentProcessProgress);
}
private List<Task> doWorkProcess(ProcessProgress pp)
{
var MetersToProcess = MeterStateCtls.Where(e => e.IsEnabled).ToList();
var listOfProcessTask = new List<Task>();
listOfProcessTask.Add(new Task<bool>(() =>
{
#region Wait for settling time (60s)
for (Int32 Time = pp.Setting.OffsetTestSettlingTime; Time >= 0; Time--)
{
if (CheckAbort(true)) { return false; }
pp.StatusLabel = $"{PredefinedMessages.ZeroflowOffsetWaitForSettling(pp.Setting.Culture)}{Time.ToString(pp.Setting.Culture)}";
Thread.Sleep(1000);
}
#endregion
var listOfSubTask = new List<Task>();
foreach (var meterctl in MetersToProcess)
{
meterctl.Meter.CurrentRecords.Clear();
listOfSubTask.Add(new Task<bool>(() =>
{
var Ok = true;
Boolean PerformCheck = true;
//Timeout calculation for offset test
//(pp.Setting.OffsetTestNumberOfLines * number of path) / 1000
//((9000 * 3) / 1000 ) = 27 min
var pataDataActivitCheck = new MultiPathDataLogContainer<int>(pp.Setting.NumberOfPaths);
var MaxTimeoutWarnings = 300;
pataDataActivitCheck.Update(null, -1);
Thread.Sleep(1800);
while (PerformCheck)
{
var offsetRecords = new List<CalibrationRecord>();
try
{
offsetRecords = meterctl.Meter.CurrentRecords.ToList();
}
catch (Exception ex)
{
try
{
offsetRecords = meterctl.Meter.CurrentRecords.ToList();
}
catch (Exception)
{
Ok = false;
PerformCheck = false;
}
}
pp.StatusLabel = ($"{PredefinedMessages.ZeroflowOffsetAqqFinished(pp.Setting.Culture)} {offsetRecords.Count}/{(pp.Setting.OffsetTestNumberOfLines * 3)}"); // "Wait until data aquisition has finished:"
Thread.Sleep(1800);
for (UInt16 PathSum = 0; PathSum < pp.Setting.NumberOfPaths; PathSum++)
{
var currentCount = offsetRecords.Count(c => c.Channel == PathSum + 1);
var oldCound = pataDataActivitCheck.Get(PathSum);
if (currentCount <= oldCound + 1)
{
pp.DebugMessage($"Warn! Receive no new lines on path {PathSum}", meterctl.Slot, "DC", meterctl.Meter.PcbId);
MaxTimeoutWarnings = MaxTimeoutWarnings - 1;
}
pataDataActivitCheck.Update(PathSum, currentCount);
}
//todo:enable timeout and canneclation token
if (MaxTimeoutWarnings <= 0)
{
pp.DebugMessage($"Fatal timeout while collecting data. Please check LED singnal. Has {offsetRecords.Count} from {pp.Setting.OffsetTestNumberOfLines * 3}", meterctl.Slot, "DC", meterctl.Meter.PcbId);
// Ok = false;
}
if (CheckAbort(Ok, meterctl)) { return Ok; }
bool testDone = true;
for (UInt16 Path = 0; Path < pp.Setting.NumberOfPaths; Path++)
{
var lstPathRecords = offsetRecords.Where(c => c.Channel == Path + 1).ToList();
if (lstPathRecords.Count(v => !v.IsValid) > pp.Setting.OffsetTestNumberOfLines * 0.1)
{
pp.DebugMessage($" To many bad data Packages {meterctl.Meter.Slot}; PATH {Path + 1}; Linecounter = {lstPathRecords.Count}", null, "DC");
Ok = false;
break;
}
if (lstPathRecords.Count < pp.Setting.OffsetTestNumberOfLines)
{
testDone = false;
}
}
if (testDone)
{
Ok = true;
PerformCheck = false;
}
if (CheckAbort(Ok, meterctl)) { return Ok; }
}
var PathDataContainerBaddata = new MultiPathDataLogContainer<List<CalibrationRecord>>(pp.Setting.NumberOfPaths);
var PathDataContainer = new MultiPathDataLogContainer<List<CalibrationRecord>>(pp.Setting.NumberOfPaths);
for (UInt16 Path = 0; Path < PathDataContainer.GetPathCount(); Path++)
{
var offsetRecords = meterctl.Meter.CurrentRecords.ToList().Where(c => (c.Channel == (Path + 1)) && c.IsValid).ToList();
PathDataContainer.Update(Path, offsetRecords);
offsetRecords = meterctl.Meter.CurrentRecords.ToList().Where(c => (c.Channel == (Path + 1)) && !c.IsValid).ToList();
PathDataContainerBaddata.Update(Path, offsetRecords);
}
#region Calculating mean values
pp.DebugMessage($"Calculating mean values", meterctl.Meter.Slot, "APP", meterctl.Meter.PcbId);
var amplitudeValuesMeanUp = new MultiPathDataLogContainer<double>(pp.Setting.NumberOfPaths);
var amplitudeValuesMeanDown = new MultiPathDataLogContainer<double>(pp.Setting.NumberOfPaths);
var DeltaTimeOfFlightAverage = new MultiPathDataLogContainer<double>(pp.Setting.NumberOfPaths);
for (UInt16 Path = 0; Path < PathDataContainer.GetPathCount(); Path++)
{
var meanAmplitudeUpV = PathDataContainer.Get(Path).Sum(ad => ad.AmplitudeUpV) / PathDataContainer.Get(Path).Count;
var meanAmplitudeDownV = PathDataContainer.Get(Path).Sum(ad => ad.AmplitudeDownV) / PathDataContainer.Get(Path).Count;
var avgDeltaTimeOfFlight = PathDataContainer.Get(Path).Sum(ad => ad.DeltaTimeOfFlightS) / PathDataContainer.Get(Path).Count;
if (meanAmplitudeUpV == 0 || meanAmplitudeDownV == 0 || avgDeltaTimeOfFlight == 0)
{
pp.DebugMessage($"Mean value is zero at {meterctl.Meter.Slot}; PATH{Path + 1}", meterctl.Meter.Slot, "DC", meterctl.Meter.PcbId);
if (pp.Setting.NumberOfPaths != 1)
{
Ok = false;
}
}
if (CheckAbort(Ok, meterctl)) { return Ok; }
amplitudeValuesMeanUp.Update(Path, meanAmplitudeUpV);
amplitudeValuesMeanDown.Update(Path, meanAmplitudeDownV);
DeltaTimeOfFlightAverage.Update(Path, avgDeltaTimeOfFlight);
}
#endregion
var BadDataCheckOK = true;
var AmplitudeCheckOK = true;
var OffsetCheckOK = true;
for (UInt16 Path = 0; Path < PathDataContainer.GetPathCount(); Path++)
{
pp.DebugMessage($"Bad data at PATH{Path + 1}:{PathDataContainerBaddata.Get(Path).Count()}", meterctl.Meter.Slot, "DC", meterctl.Meter.PcbId);
if (PathDataContainerBaddata.Get(Path).Count() > pp.Setting.OffsetTestBadDataLimit)
{
BadDataCheckOK = false;
pp.DebugMessage($"Bad datacheck failed!", meterctl.Meter.Slot, "DC", meterctl.Meter.PcbId);
}
pp.DebugMessage($"Average positive amplitude, PATH{(Path + 1)}: {Math.Round(amplitudeValuesMeanUp.Get(Path), 2).ToString("000.00")}mV", meterctl.Meter.Slot, "DC", meterctl.Meter.PcbId);
pp.DebugMessage($"Average negative amplitude, PATH{(Path + 1)}: {Math.Round(amplitudeValuesMeanDown.Get(Path), 2).ToString("000.00")}mV", meterctl.Meter.Slot, "DC", meterctl.Meter.PcbId);
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average positive amplitude PATH {(Path + 1)}", $"{Math.Round(amplitudeValuesMeanUp.Get(Path), 2).ToString("000.00")}mV");
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average negative amplitude PATH {(Path + 1)}", $"{Math.Round(amplitudeValuesMeanDown.Get(Path), 2).ToString("000.00")}mV");
if (pp.Setting.MeterSize == Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize.DN200 || pp.Setting.MeterSize == Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize.US8)
{
pp.Setting.OffsetTestLowerVoltageLimitMV = 180;
}
if ((amplitudeValuesMeanUp.Get(Path) > pp.Setting.OffsetTestUpperVoltageLimitMV) ||
(amplitudeValuesMeanUp.Get(Path) < pp.Setting.OffsetTestLowerVoltageLimitMV) ||
(amplitudeValuesMeanDown.Get(Path) < pp.Setting.OffsetTestLowerVoltageLimitMV) ||
(amplitudeValuesMeanDown.Get(Path) > pp.Setting.OffsetTestUpperVoltageLimitMV))
{
AmplitudeCheckOK = false;
pp.DebugMessage($"Amplitude check failed!", meterctl.Meter.Slot, "APP", meterctl.Meter.PcbId);
}
pp.DebugMessage($"Average delta time of flight valuePATH{(Path + 1)}: Raw{DeltaTimeOfFlightAverage.Get(Path)} -> in picoseconds= {Math.Round((DeltaTimeOfFlightAverage.Get(Path) / (Math.Pow(2, 38) * Math.Pow(10, 12))), 2).ToString("000.00")}", meterctl.Meter.Slot, "APP", meterctl.Meter.PcbId);
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average delta time of flight value PATH {(Path + 1)} RAW ", $"{DeltaTimeOfFlightAverage.Get(Path)}");
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average delta time of flight value PATH {(Path + 1)} picoseconds ", $"{Math.Round((DeltaTimeOfFlightAverage.Get(Path) / (Math.Pow(2, 38) * Math.Pow(10, 12))), 2).ToString("000.00")}");
if ((DeltaTimeOfFlightAverage.Get(Path) > pp.Setting.OffsetTestOffsetLimitPS) ||
(DeltaTimeOfFlightAverage.Get(Path) < -pp.Setting.OffsetTestOffsetLimitPS))
{
pp.DebugMessage($"Delta time of flight check failed", meterctl.Meter.Slot, "APP", meterctl.Meter.PcbId);
OffsetCheckOK = false;
}
}
if (!BadDataCheckOK
|| !AmplitudeCheckOK
|| !OffsetCheckOK)
{
pp.DebugMessage($"Skip offset test at least one test is failed", meterctl.Meter.Slot, "APP", meterctl.Meter.PcbId);
if (pp.Setting.NumberOfPaths != 1)
{
if (CheckAbort(false, meterctl)) { return false; }
}
}
Ok = meterctl.Meter.ReLogin();
if (CheckAbort(Ok, meterctl)) { return Ok; }
for (UInt16 Path = 0; Path < DeltaTimeOfFlightAverage.GetPathCount(); Path++)
{
var OffsetValue = (Int32)((DeltaTimeOfFlightAverage.Get(Path) * Math.Pow(2, 40)));
pp.StatusLabel = ($"{PredefinedMessages.WaitUntilRegisterWriteFinished(pp.Setting.Culture)}");
String RegValue = String.Empty;
switch (Path)
{
case 0:
RegValue = Register.Genesisflow.ZeroOffset1;
break;
case 1:
RegValue = Register.Genesisflow.ZeroOffset2;
break;
case 2:
RegValue = Register.Genesisflow.ZeroOffset3;
break;
default:
System.Windows.Forms.MessageBox.Show($"Path number incorrect {Path}");
break;
};
if (pp.Setting.NumberOfPaths != 1)
{
Ok = WriteRegisterSafe(meterctl.Meter, $"Zero flow offset Path {Path + 1}", RegValue, OffsetValue);
if (CheckAbort(Ok, meterctl)) { return Ok; }
}
else
{
Ok = WriteRegisterSafe(meterctl.Meter, $"Zero flow offset Path {Path + 1}", RegValue, OffsetValue);
Ok = true;
}
}
return Ok;
}));
}
listOfSubTask.ForEach(t => t.Start());
while (listOfSubTask.Any(t => !t.IsCompleted))
{
Thread.Sleep(1000);
}
return true;
}));
return listOfProcessTask;
}
}
}