Compare commits

..
Author SHA1 Message Date
michal c79688dc0c Add GenesisCorrections implementation for smart meter calibration and worker thread management. 2026-05-04 11:11:04 +02:00
michal 74bcbaf12d Update SmartCommunicationForm to improve combo box initialization and null-check handling. Integrate SmartCommunicationForm into GenesisFullCommunication. 2026-04-24 09:46:58 +02:00
michal a3821d722b Refactor GenesisFullCommunication: simplify TestMethodCfg class, update TestMethodCfgCtrl logic, and remove unused imports. 2026-04-24 08:18:30 +02:00
michal 9339683a0e Refactor GenesisCommunication to GenesisFullCommunication, including namespace updates, class renaming, file relocations, and csproj adjustments. 2026-04-23 09:53:13 +02:00
michal 7170da4a70 Add GenesisCommunication test methods and related components:
- Introduce `TestMethod`, `SequenceConditionOp`, and `Factory` for `GenesisCommunication`.
- Add `TestMethodCfgCtrl` and its designer for test configuration UI.
- Update `.csproj` to include new files.
2026-04-22 10:18:42 +02:00
michal 842f009b42 Increment assembly version to 3.9.3058.1 and fix logging format issue in FlowMeter initialization. 2026-04-21 07:43:35 +02:00
michal 7f30ca0cd1 Merge branch 'develop/SLM-PT50_genesisDirectDecode' into develop/SLM-PT50_genesisDirectDecode_morisville
# Conflicts:
#	TBF/Properties/AssemblyInfo.cs
#	TBF/Rig/RegisterReaders/GenesisRegReader/implementations/GenesisSmartReader.cs
2026-04-20 14:25:13 +02:00
michal 93e207c211 Update GenesisSmartReader for refined start/end marker logic, add _endDeltaSeconds property, and improve telegram index resolution methods. Increment assembly version to 3.9.3031.1. 2026-04-20 13:25:25 +02:00
marekf 64cafc088a Merge branch 'bugfix/Flow-meter-in-parallel-reverse-bug' into develop/SLM-PT50 2026-04-20 12:45:25 +02:00
marekf 8a0da27a07 Fixed RegValve + FlowMetersInParallel - incorrect NominalFreq sum 2026-04-20 12:39:51 +02:00
michal 5a8478e782 Refactor GenesisSmartReader Q3 calibration tests and logic:
- Expand Q3 calibration tests with diverse scenarios in `GenesisSmartReader_Q3Test`.
- Introduce channel-specific validation for calibration tests.
- Adjust methods for Q3 calibration in `GenesisSmartReader` to support per-channel factors.
- Add utilities for preparing simulation data and refinements for test consistency.
- Update `CliRunner` with improved task management, timeout handling, and logging enhancements.
2026-04-17 16:05:16 +02:00
marekf 368cd95114 Bug (fixing) RegValve OK, FlowMeterInParallel NOK 2026-04-15 10:50:27 +02:00
marekf 3376ac41b4 Merge branch 'develop/SLM-PT50_genesisDirectDecode' of http://87.197.120.129:33300/michal/tbf into develop/SLM-PT50 2026-04-11 11:54:37 +02:00
marekf f9181fee74 Fixed SelectComponentDlg > missing assignment sharedSearchForListBox1.ListBoxEx = availCmpntsLstBox, because of this the application crashes 2026-04-11 11:04:00 +02:00
marekf ff5954d85b Bugfix FlowMeterInParallel and RegValve OUT OF RANGE regulation part1 2026-04-02 12:02:26 +02:00
marekf c09e266b2c Bugfix ComponentPropertiesDlg frm size 140x80 2026-04-01 12:12:04 +02:00
43 changed files with 7257 additions and 788 deletions
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("3.9.3056.1")]
[assembly: AssemblyFileVersion("3.9.3056.1")]
[assembly: AssemblyVersion("3.9.3058.1")]
[assembly: AssemblyFileVersion("3.9.3058.1")]
@@ -175,8 +175,8 @@ namespace TBF.Rig.ControlBoard.Uni
double reqFlowLo = (0.7 * qFrom) + (0.3 * reqFlowAve); /// Move the lower limit 15% of the range up
double reqFlowHi = (0.7 * qTo) + (0.3 * reqFlowAve); /// Move the upper limit 15% of the range down
///
uniCB.SetFlow(false, regV.Idx1, 2000.0 * reqFlowLo / flowMeter.NominalFlow,
2000.0 * reqFlowHi / flowMeter.NominalFlow);
uniCB.SetFlow(false, regV.Idx1, flowMeter.NominalFreq * reqFlowLo / flowMeter.NominalFlow,
flowMeter.NominalFreq * reqFlowHi / flowMeter.NominalFlow);
if (readDivTransition)
{
/// Schedule reading diverter transition data
+65 -4
View File
@@ -803,12 +803,60 @@ namespace TBF.Rig.ControlBoard.Uni
/// </summary>
public void SetFlow(bool isFromUI, int regVId, double freqLo, double freqHi, int regulationMinStep = 0)
{
if (IsUIBlocked && isFromUI) return;
LiveLogDiag.Log1("----------------------------------------");
LiveLogDiag.Log1(
"SetFlow() >> ENTER isFromUI={0} regVId={1} freqLo={2} freqHi={3} regulationMinStep={4} IsUIBlocked={5}",
isFromUI, regVId, freqLo, freqHi, regulationMinStep, IsUIBlocked);
actionQueue.Enqueue(Action.SetFlow(isFromUI, regVId, freqLo, freqHi, Convert.ToInt32(Math.Round(Devices.PidCoef)), 200, regulationMinStep));
log.InfoFormat("Enqueue( SetFlow(rv={0}, fLo={1}, fHi={2}, pid={3}) )", regVId, freqLo, freqHi, Convert.ToInt32(Math.Round(Devices.PidCoef)));
if (IsUIBlocked && isFromUI)
{
LiveLogDiag.Log1(
"SetFlow() >> EXIT (UI BLOCKED) isFromUI={0}",
isFromUI);
return;
}
foreach (var a in actionQueue) log.DebugFormat(" {0}", a);
int pid = Convert.ToInt32(Math.Round(Devices.PidCoef));
int fixedParam = 200;
LiveLogDiag.Log1(
"SetFlow() >> PREPARE pid={0} fixedParam={1} regulationMinStep={2}",
pid, fixedParam, regulationMinStep);
var action = Action.SetFlow(
isFromUI,
regVId,
freqLo,
freqHi,
pid,
fixedParam,
regulationMinStep);
LiveLogDiag.Log1(
"SetFlow() >> ACTION CREATED: rv={0} fLo={1} fHi={2} pid={3} p6={4} minStep={5}",
regVId, freqLo, freqHi, pid, fixedParam, regulationMinStep);
actionQueue.Enqueue(action);
LiveLogDiag.Log1(
"SetFlow() >> ENQUEUED actionQueue.Count={0}",
actionQueue.Count);
log.InfoFormat(
"Enqueue( SetFlow(rv={0}, fLo={1}, fHi={2}, pid={3}) )",
regVId, freqLo, freqHi, pid);
int i = 0;
foreach (var a in actionQueue)
{
LiveLogDiag.Log1(
"SetFlow() >> QUEUE[{0}] = {1}",
i++, a);
log.DebugFormat(" {0}", a);
}
LiveLogDiag.Log1("SetFlow() >> EXIT");
LiveLogDiag.Log1("----------------------------------------");
}
public void StartTest(bool isFromUI, int flowMId, int divId, int divThreshold,
@@ -981,5 +1029,18 @@ namespace TBF.Rig.ControlBoard.Uni
{
/// TODO
}
/// <summary>
/// Logging
/// For activation use compilation condition: LIVELOGDIAG_FlowMeter_cs
/// </summary>
static class LiveLogDiag
{
[Conditional("LIVELOGDIAG_UniCB_cs")]
public static void Log1(string format, params object[] args)
{
LiveLogCache.Instance.AddLog("UniCB.cs LOG>> " + string.Format(format, args));
}
}
}
}
@@ -633,8 +633,31 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
public double TimestampSecEndCh1 => NoSamples ? 0 : GetCachedTime(_recalculatedStartEndByChannel, 0, 1);
public double TimestampSecEndCh2 => NoSamples ? 0 : GetCachedTime(_recalculatedStartEndByChannel, 1, 1);
public double TimestampSecEndCh3 => NoSamples ? 0 : GetCachedTime(_recalculatedStartEndByChannel, 2, 1);
public double VolumeLtrStartRaw => NoSamples ? 0 : AverageCachedVolume(_rawStartEndByChannel, 0);
public double VolumeLtrEndRaw => NoSamples ? 0 : AverageCachedVolume(_rawStartEndByChannel, 1);
public double VolumeLtrStartAverage => NoSamples ? 0 : AverageCachedVolume(_recalculatedStartEndByChannel, 0);
public double VolumeLtrEndAwerage => NoSamples ? 0 : AverageCachedVolume(_recalculatedStartEndByChannel, 1);
public double VolumeLtrStartRawRaw => NoSamples ? 0 : AverageCachedVolume(_rawStartEndByChannel, 0);
public double VolumeLtrEndRawRaw => NoSamples ? 0 : AverageCachedVolume(_rawStartEndByChannel, 1);
public double VolumeLtrStartRawCh1 => NoSamples ? 0 : GetCachedVolume(_rawStartEndByChannel, 0, 0);
public double VolumeLtrStartRawCh2 => NoSamples ? 0 : GetCachedVolume(_rawStartEndByChannel, 1, 0);
public double VolumeLtrStartRawCh3 => NoSamples ? 0 : GetCachedVolume(_rawStartEndByChannel, 2, 0);
public double VolumeLtrEndRawCh1 => NoSamples ? 0 : GetCachedVolume(_rawStartEndByChannel, 0, 1);
public double VolumeLtrEndRawCh2 => NoSamples ? 0 : GetCachedVolume(_rawStartEndByChannel, 1, 1);
public double VolumeLtrEndRawCh3 => NoSamples ? 0 : GetCachedVolume(_rawStartEndByChannel, 2, 1);
public double TimestampSecStartRawCh1 => NoSamples ? 0 : GetCachedTime(_rawStartEndByChannel, 0, 0);
public double TimestampSecStartRawCh2 => NoSamples ? 0 : GetCachedTime(_rawStartEndByChannel, 1, 0);
public double TimestampSecStartRawCh3 => NoSamples ? 0 : GetCachedTime(_rawStartEndByChannel, 2, 0);
public double TimestampSecEndRawCh1 => NoSamples ? 0 : GetCachedTime(_rawStartEndByChannel, 0, 1);
public double TimestampSecEndRawCh2 => NoSamples ? 0 : GetCachedTime(_rawStartEndByChannel, 1, 1);
public double TimestampSecEndRawCh3 => NoSamples ? 0 : GetCachedTime(_rawStartEndByChannel, 2, 1);
@@ -643,7 +666,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
{
get
{
return VolumeLtrStartRaw;
return VolumeLtrStartAverage;
}
}
@@ -652,7 +675,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
{
get
{
return VolumeLtrEndRaw;
return VolumeLtrEndAwerage;
}
}
@@ -1302,7 +1325,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
try
{
log.DebugFormat("DataStreamPostProcessing() - harcoded call GetQ3Calibration(200.0, 120.0, 15625.0);");
GetQ3Calibration(200.0, 120.0, 15625.0);
SetQ3Calibration(new double[]{15625.0,15625.0,15625.0 });
CalculateQ3Calibration(200.0, 120.0);
}
catch (Exception ex)
{
@@ -3885,20 +3909,61 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
}
}
#endregion
private bool isQ3CalibValid = false;
private double q3Calib = 0;
private double[] q3CalibInitial = {Double.NaN,Double.NaN,Double.NaN};
private bool[] isChQ3CalibValid = { false,false,false};
private double[] q3CalibCh = {Double.NaN,Double.NaN,Double.NaN};
public bool Q3CalibValid { get => isQ3CalibValid; }
public double Q3CalibValue { get => q3Calib; }
public bool Q3CalibValid
{
get
{
foreach (var b in isChQ3CalibValid)
{
if (!b)
return false;
}
public void GetQ3Calibration(double refVolume, double refTime, double initCalibFactor)
return true;
}
}
public double[] Q3CalibValue { get => q3CalibInitial; }
public bool Q3Calib_Ch1Valid { get => isChQ3CalibValid[0]; }
public bool Q3Calib_Ch2Valid { get => isChQ3CalibValid[1]; }
public bool Q3Calib_Ch3Valid { get => isChQ3CalibValid[2]; }
public double Q3Calib_Ch1Value { get => q3CalibCh[0]; }
public double Q3Calib_Ch2Value { get => q3CalibCh[1]; }
public double Q3Calib_Ch3Value { get => q3CalibCh[2]; }
void SetQ3Calibration(double[] q3CalibInitial) { this.q3CalibInitial = q3CalibInitial; }
public void CalculateQ3Calibration(double refVolume, double refTime)
{
GetQ3Calibration(refVolume, refTime, q3CalibInitial, ref isChQ3CalibValid, ref q3CalibCh);
}
public void GetQ3Calibration(double refVolume, double refTime, double[] initCalibFactor, ref bool[] isChQ3CalibValid, ref double[] q3CalibCh)
{
log.Debug("=== Q3 CALIBRATION START ===");
isQ3CalibValid = false;
q3Calib = 0.0;
//initialisation
for (int iChannel = 0; iChannel < ChannelCount; iChannel++)
{
q3CalibCh[iChannel] = 0.0;
isChQ3CalibValid[iChannel] = false;
}
foreach (var init in initCalibFactor)
{
if (Double.IsNaN(init))
{
log.Error("Q3 Calibration: Initial calibration value is NaN");
return;
}
}
log.Debug($"Inputs: refVolume={refVolume}, refTime={refTime}, initCalibFactor={initCalibFactor}");
@@ -3914,7 +3979,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
return;
}
if (refVolume <= 0 || refTime <= 0 || initCalibFactor <= 0)
if (refVolume <= 0 || refTime <= 0)
{
log.Debug("EXIT: Invalid input values (<= 0)");
return;
@@ -3931,6 +3996,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
for (int iChannel = 0; iChannel < ChannelCount; iChannel++)
{
var channelData = _rawStartEndByChannel[iChannel];
if (channelData == null || channelData.Length < 2)
@@ -3938,7 +4004,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
log.Debug($"Channel {iChannel}: SKIPPED (no data)");
continue;
}
var start = channelData[0];
var end = channelData[1];
@@ -3962,10 +4028,11 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
log.Debug($" End: T={end.TimestampExt}, V={end.VolumeRawExt}");
log.Debug($" Delta: dT={deltaTime}, dV={deltaVolume}");
double recalculatedDeltaVolume = 0.0f;
if (deltaTime > 0)
{
double timeCoef = refTime / deltaTime;
double recalculatedDeltaVolume = deltaVolume * timeCoef;
double timeCoef = refTime / deltaTime; //?
recalculatedDeltaVolume = deltaVolume * timeCoef;
recalculatedVariablesByChannel[iChannel][1].VolumeRawExt =
recalculatedVariablesByChannel[iChannel][0].VolumeRawExt + recalculatedDeltaVolume;
@@ -3979,52 +4046,18 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
recalculatedVariablesByChannel[iChannel][0].TimestampExt = 0;
recalculatedVariablesByChannel[iChannel][1].TimestampExt = refTime;
}
double scaling = 15625.0;
log.Debug($"Scaling={scaling}");
if (scaling <= 0)
{
log.Debug("EXIT: scaling <= 0");
return;
}
double avgRawVolume = AverageCachedVolume(recalculatedVariablesByChannel, 0);
log.Debug($"AverageCachedVolume={avgRawVolume}");
if (avgRawVolume <= 0)
{
log.Debug("EXIT: avgRawVolume <= 0");
return;
}
double measuredVolume = avgRawVolume / scaling;
log.Debug($"MeasuredVolume={measuredVolume}");
if (measuredVolume <= 0)
{
log.Debug("EXIT: measuredVolume <= 0");
return;
}
q3Calib = (refVolume / measuredVolume) * initCalibFactor;
log.Debug($"Q3Calib (raw)={q3Calib}");
double diffPercent =
Math.Abs((q3Calib - initCalibFactor) / initCalibFactor) * 100.0;
log.Debug($"DiffPercent={diffPercent}%");
isQ3CalibValid = diffPercent <= 5.0;
log.Debug($"Validation: {(isQ3CalibValid ? "VALID" : "INVALID")}");
if (!isQ3CalibValid)
{
q3Calib = 0.0;
log.Debug("Q3Calib reset to 0 due to invalid result");
if (Math.Abs(recalculatedDeltaVolume) <= Double.Epsilon)
{
log.Debug($"Channel {iChannel}: recalculatedDeltaVolume is zero");
continue;
}
q3CalibCh[iChannel] = (refVolume / recalculatedDeltaVolume) * initCalibFactor[iChannel];
double diffPercent = Math.Abs((initCalibFactor[iChannel] - q3CalibCh[iChannel] ) / initCalibFactor[iChannel]) * 100.0;
isChQ3CalibValid[iChannel] = diffPercent <= 5.0;
log.Debug($"Calculated Q3Calib Ch[{iChannel}] ={q3CalibCh[iChannel]} DiffPercent={diffPercent}% isValid[{isChQ3CalibValid[iChannel]}] IninitCalibFactor={initCalibFactor}");
}
log.Debug("=== Q3 CALIBRATION END ===");
@@ -13,46 +13,29 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
public class CliRunner
{
//static readonly ILog log = LogManager.GetLogger(typeof(CliRunner));
private readonly ILog log;
private List<Task> taskPool = new List<Task>();
private long startTime;
private long incommingTime;
public List<Task> TaskPool { get { return taskPool; } }
public void AddTask(Task task) { taskPool.Add(task); }
public void WaitAll() { Task.WaitAll(taskPool.ToArray()); }
public void Clear() { taskPool.Clear(); }
public void CancelAll() { Task.WhenAll(taskPool).ContinueWith(t => { }); }
private readonly List<CliTaskInfo> taskPool = new List<CliTaskInfo>();
private long startTimeMs;
private long incommingTimeMs;
public void StartAll()
public List<CliTaskInfo> TaskPool
{
taskPool.ForEach(t => t.Start());
}
public bool AreTasksDone()
{
return taskPool.All(task => task.IsCompleted);
get { return taskPool; }
}
public long StartTime
{
get => startTime;
get { return startTimeMs; }
}
public long IncommingTime
{
get => incommingTime;
get { return incommingTimeMs; }
}
public bool TimeOutReceived(long timeout)
{
return (DateTime.Now.Ticks - startTime) > timeout;
}
public CliRunner(bool isCliLogging)
{
startTime = DateTime.Now.Ticks;
ResetStartTime();
if (isCliLogging)
{
@@ -60,88 +43,180 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
@"C:\TBF\Logs\CliRunner.txt",
10, // maxFileSizeMB
7, // maxBackups
10,
7,
log4net.Core.Level.Debug,
true, // zipRolledFiles
true, // singleZipPerDay
TimeSpan.FromMinutes(2) // zipScanInterval
true,
true,
TimeSpan.FromMinutes(2)
);
}
catch (Exception ex)
{
// Fallback to console or handle gracefully
Console.WriteLine($"Failed to initialize logger: {ex.Message}");
}
}
}
/// <summary>
///
/// </summary>
/// <param name="fileName"></param>
/// <param name="args"></param>
/// <typeparam name="T"></typeparam>
public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
public void ResetStartTime()
{
var task = SendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
taskPool.Add(task);
startTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
public void AddSendAsync(string fileName, string args)
{
var task = SendAsync(fileName, args);
taskPool.Add(task);
}
public async Task<string> SendAsync(string fileName, string args, CancellationToken ct = default)
{
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = args,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
process.Start();
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
try
public void Clear()
{
foreach (var item in taskPool)
{
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
}
catch (OperationCanceledException)
{
if (!process.HasExited)
try
{
item?.Cts?.Dispose();
}
catch
{
process.Kill();
}
throw;
try
{
if (item?.Process != null)
{
item.Process.Dispose();
}
}
catch
{
}
}
//comming answer from serial port - good place for time stamp
incommingTime = DateTime.Now.Ticks;
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
log?.Debug(allOutput);
return allOutput;
taskPool.Clear();
}
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
public void WaitAll()
{
var task = RunAndCaptureJsonAsync<T>(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
taskPool.Add(task);
var tasks = taskPool
.Where(t => t != null && t.Task != null)
.Select(t => t.Task)
.ToArray();
if (tasks.Length == 0)
return;
try
{
Task.WaitAll(tasks);
}
catch (AggregateException)
{
RefreshTaskStates();
}
}
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args, CancellationToken ct = default) where T : new()
public bool AreTasksDone()
{
RefreshTaskStates();
return taskPool.Count > 0 && taskPool.All(t => t.State != CliTaskState.Running);
}
public bool TimeOutReceived(long timeoutMs)
{
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
return (nowMs - startTimeMs) > timeoutMs;
}
public void RefreshTaskStates()
{
foreach (var item in taskPool)
{
if (item == null || item.Task == null)
continue;
if (item.State == CliTaskState.TimedOut)
continue;
if (!item.Task.IsCompleted)
{
item.State = CliTaskState.Running;
}
else if (item.Task.IsCanceled)
{
item.State = CliTaskState.Canceled;
}
else if (item.Task.IsFaulted)
{
item.State = CliTaskState.Faulted;
}
else
{
item.State = CliTaskState.Completed;
}
}
}
public void CancelUndoneTasksAsTimedOut()
{
foreach (var item in taskPool)
{
if (item == null || item.Task == null)
continue;
if (item.Task.IsCompleted)
{
if (item.Task.IsCanceled)
item.State = CliTaskState.Canceled;
else if (item.Task.IsFaulted)
item.State = CliTaskState.Faulted;
else
item.State = CliTaskState.Completed;
continue;
}
item.State = CliTaskState.TimedOut;
try
{
item.Cts?.Cancel();
}
catch (Exception ex)
{
log?.Warn("Cancel token failed", ex);
}
try
{
if (item.Process != null && !item.Process.HasExited)
{
item.Process.Kill();
}
}
catch (Exception ex)
{
log?.Warn("Kill process failed", ex);
}
}
}
public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
{
AddSendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
}
public void AddSendAsync(string fileName, string args)
{
ResetStartTime();
var cts = new CancellationTokenSource();
var info = new CliTaskInfo
{
Cts = cts,
Name = "SendAsync"
};
var task = SendAsync(fileName, args, info, cts.Token);
info.Task = task;
taskPool.Add(info);
}
public async Task<string> SendAsync(string fileName, string args, CliTaskInfo info, CancellationToken ct = default)
{
var psi = new ProcessStartInfo
{
@@ -153,80 +228,210 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
CreateNoWindow = true
};
using var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
process.Start();
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true })
{
info.Process = process;
var stdoutTask = process.StandardOutput.ReadToEndAsync();
var stderrTask = process.StandardError.ReadToEndAsync();
try
{
process.Start();
await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
string allOutput = (stdoutTask.Result ?? "") + (stderrTask.Result ?? "");
log?.Debug(allOutput);
try
{
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
}
catch (OperationCanceledException)
{
if (info.State != CliTaskState.TimedOut)
info.State = CliTaskState.Canceled;
string json = ExtractJson(allOutput);
if (TryJsonStringDeserialize(json, out T result)) return result;
return default;
if (!process.HasExited)
{
process.Kill();
}
throw;
}
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
log?.Debug(allOutput);
info.State = CliTaskState.Completed;
return allOutput;
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
info.State = CliTaskState.Faulted;
log?.Error("SendAsync failed", ex);
throw;
}
finally
{
info.Process = null;
}
}
}
public bool TryJsonStringDeserialize<T>(string json, out T runAndCaptureJsonAsync) where T : new()
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
{
AddRunAndCaptureJsonAsync<T>(
data.SerialPortCmdClientPath,
data.DefaultArgSettings(eMeterArg));
}
public void AddRunAndCaptureJsonAsync<T>(string fileName, string args) where T : new()
{
ResetStartTime();
var cts = new CancellationTokenSource();
var info = new CliTaskInfo
{
Cts = cts,
Name = $"RunAndCaptureJsonAsync<{typeof(T).Name}>"
};
var task = RunAndCaptureJsonAsync<T>(fileName, args, info, cts.Token);
info.Task = task;
taskPool.Add(info);
}
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args, CliTaskInfo info, CancellationToken ct = default) where T : new()
{
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = args,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true })
{
info.Process = process;
try
{
process.Start();
var stdoutTask = process.StandardOutput.ReadToEndAsync();
var stderrTask = process.StandardError.ReadToEndAsync();
try
{
await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
}
catch (OperationCanceledException)
{
if (info.State != CliTaskState.TimedOut)
info.State = CliTaskState.Canceled;
if (!process.HasExited)
{
process.Kill();
}
throw;
}
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
string allOutput = (stdoutTask.Result ?? "") + (stderrTask.Result ?? "");
log?.Debug(allOutput);
string json = ExtractJson(allOutput);
T result;
if (TryJsonStringDeserialize(json, out result))
{
info.State = CliTaskState.Completed;
return result;
}
info.State = CliTaskState.Completed;
return default(T);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
info.State = CliTaskState.Faulted;
log?.Error("RunAndCaptureJsonAsync failed", ex);
throw;
}
finally
{
info.Process = null;
}
}
}
public bool TryJsonStringDeserialize<T>(string json, out T value) where T : new()
{
if (json != null)
{
try
{
runAndCaptureJsonAsync = JsonConvert.DeserializeObject<T>(json);
value = JsonConvert.DeserializeObject<T>(json);
return true;
}
catch (Exception ex)
{
log.Debug(ex.Message);
runAndCaptureJsonAsync = TryConvert<T>(json);
log?.Debug(ex.Message);
value = TryConvert<T>(json);
return true;
}
}
runAndCaptureJsonAsync = default;
value = default(T);
return false;
}
private static T TryConvert<T>(string json) where T : new()
{
T obj = new T();
T obj = new T();
try
try
{
JObject jObject = JObject.Parse(json);
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
JObject jObject = JObject.Parse(json);
if (!prop.CanWrite)
continue;
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
JToken token;
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
{
if (!prop.CanWrite) continue;
JToken token;
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
try
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(obj, value);
}
catch
{
try
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(obj, value);
}
catch
{
// leave default if conversion fails
}
}
// else → keep default value
}
}
catch (Exception ex)
{
Console.WriteLine($"TryConvert failed: {ex.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"TryConvert failed: {ex.Message}");
}
return obj;
return obj;
}
public string ExtractJson(string text)
@@ -241,6 +446,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
return null;
}
internal void AddTaskForTest(Task task, string name = "TestTask", CancellationTokenSource cts = null)
{
taskPool.Add(new CliTaskInfo
{
Task = task,
Cts = cts,
Name = name,
State = task.IsCompleted
? (task.IsCanceled ? CliTaskState.Canceled :
task.IsFaulted ? CliTaskState.Faulted :
CliTaskState.Completed)
: CliTaskState.Running
});
}
}
}
@@ -0,0 +1,25 @@
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
public class CliTaskInfo
{
public Task Task { get; set; }
public CancellationTokenSource Cts { get; set; }
public Process Process { get; set; }
public CliTaskState State { get; set; } = CliTaskState.Running;
public string Name { get; set; }
public bool UseResult
{
get
{
return State == CliTaskState.Completed
&& Task != null
&& Task.Status == TaskStatus.RanToCompletion;
}
}
}
}
@@ -0,0 +1,13 @@
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
public enum CliTaskState
{
Running,
Completed,
TimedOut,
Canceled,
Faulted
}
}
@@ -336,10 +336,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
/// for debug purposes what time will consume answer
/// </summary>
private long startTimeInMilis = -1, fullTimeInMilis = -1;
/// 30 seconds
private static long SafetyTimeOut = 30 * 1000;
private long incommingTime = -1;
private bool _lastOpTimedOut;
/// 30 seconds
public long DeltaTime { get{return fullTimeInMilis;}}
public long IncommingTime { get{return incommingTime;}}
@@ -356,108 +358,146 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
if (_currentOp == CurrentPoseidonOp.SendStartDataStream)
{
CliRunner.Clear();
_lastOpTimedOut = false;
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.AllParams);
return Event.Busy;
_currentOp = CurrentPoseidonOp.SendStartDataStream_Runing;
return Event.Busy;
}
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Runing)
{
if (CliRunner.AreTasksDone()
|| CliRunner.TimeOutReceived(SafetyTimeOut))
if (CliRunner.AreTasksDone())
{
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
}
return Event.Busy;
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
{
_lastOpTimedOut = true;
CliRunner.CancelUndoneTasksAsTimedOut();
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
}
return Event.Busy;
}
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Done)
{
var firstTask = CliRunner.TaskPool.FindLast(t => t is Task<string>);
var firstTaskInfo = CliRunner.TaskPool
.FindLast(t => t.Task is Task<string> && t.UseResult);
if (firstTask != null && firstTask is Task<string>)
if (firstTaskInfo != null)
{
string data = null;
data = (firstTask as Task<string>).Result;
var task = (Task<string>)firstTaskInfo.Task;
string data = task.Result;
if (data != null && TryGetDeviceId(data, out wmSerialNr))
if (!string.IsNullOrEmpty(data))
{
TryGetDeviceId(data, out wmSerialNr);
}
}
else if (_lastOpTimedOut)
{
log.Warn(
$"PoseidonReader {Name}: SendStartDataStream timed out, no completed result will be used.");
}
_currentOp = CurrentPoseidonOp.Done;
CliRunner.Clear();
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
return Event.Done;
}
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
{
startTimeInMilis = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
startTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
incommingTime = -1;
_isReadingStart = (_currentOp == CurrentPoseidonOp.ReadDataStream_Start);
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
CliRunner.Clear();
_lastOpTimedOut = false;
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
SerialPortData.EMeterArg.AllParams);
_currentOp = CurrentPoseidonOp.ReadDatastream_Running;
return Event.Busy;
}else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
}
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
{
if (CliRunner.AreTasksDone()
|| CliRunner.TimeOutReceived(SafetyTimeOut))
if (CliRunner.AreTasksDone())
{
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
//set time stamp - end of reading
incommingTime = CliRunner.IncommingTime;
}
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
{
_lastOpTimedOut = true;
CliRunner.CancelUndoneTasksAsTimedOut();
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
incommingTime = CliRunner.IncommingTime;
}
return Event.Busy;
}
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Done)
{
fullTimeInMilis = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - startTimeInMilis;
log.Debug($"PoseidonReader.Run() Name= {Cfg.Name} fullTimeInMilis = {fullTimeInMilis} ");
JsonDataFromPoseidon data = null;
var first = CliRunner.TaskPool.FindLast(t => t is Task<JsonDataFromPoseidon>);
if (first != null && first is Task<JsonDataFromPoseidon>)
{
data = (first as Task<JsonDataFromPoseidon>).Result;
fullTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - startTimeInMilis;
log.Debug($"PoseidonReader.Run() Name= {Cfg.Name} fullTimeInMilis = {fullTimeInMilis}");
//GET serial number
JsonDataFromPoseidon data = null;
var firstTaskInfo = CliRunner.TaskPool
.FindLast(t => t.Task is Task<JsonDataFromPoseidon> && t.UseResult);
if (firstTaskInfo != null)
{
var task = (Task<JsonDataFromPoseidon>)firstTaskInfo.Task;
data = task.Result;
}
else
{
if (_lastOpTimedOut)
{
log.Warn($"PoseidonReader {Name}: ReadDatastream timed out, no completed result available.");
}
else
{
log.Warn("No completed JsonDataFromPoseidon task available.");
}
}
if (data != null)
{
if (string.IsNullOrEmpty(wmSerialNr))
{
try
{
wmSerialNr = data?.DeviceId ?? wmSerialNr;
wmSerialNr = data.DeviceId ?? wmSerialNr;
}
catch (Exception e)
{
log.Error("Serial Nr - parse error!");
log.Error("Serial Nr - parse error!", e);
}
}
//GET volume
if (data != null && Double.TryParse(data.Reading, out double Volume))
double volume;
if (Double.TryParse(data.Reading, out volume))
{
double VolumeLi = Units.ConvertFrom(Unit.USgal, Volume);
//double VolumeM3 = Units.ConvertTo(Unit.m3, VolumeLi);
if (_isReadingStart)
{
//volume
beginWMState = VolumeLi;
}
else
{
//volume
endWMState = VolumeLi;
}
}
double volumeLi = Units.ConvertFrom(Unit.USgal, volume);
if (_isReadingStart)
beginWMState = volumeLi;
else
endWMState = volumeLi;
}
}
//Finish reading and loop
_currentOp = CurrentPoseidonOp.Done;
CliRunner.Clear();
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
return Event.Done;
}
return Event.None;
return Event.None;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
+3 -1
View File
@@ -9,6 +9,7 @@ using log4net;
using log4net.Repository.Hierarchy;
using TBF.Rig.Generic;
using TBF.Rig.Sequences;
using TBF.Rig.TestMethods.GenesisFullCommunication;
namespace TBF.Rig
{
@@ -192,7 +193,8 @@ namespace TBF.Rig
new TestMethods.FlyingStartFirstRepetWithMassColl.HeatMeters.Factory(),
new TestMethods.FlyingStartTankCollection.Single.Factory(),
new TestMethods.FlyingStartTankCollection.Compound.Factory(),
new TestMethods.GenesisCommunication.GenesisHead.Factory(),
new TestMethods.GenesisCommunication.GenesisHead.Factory(), // german implementation of the Genesis communication protocol
new Factory(),
new TestMethods.GrabImage.Factory(),
new TestMethods.iPerlCommunication.TestMethodFactory(), /// iPerlCommunication
new TestMethods.LeakTest.Factory(),
@@ -1396,18 +1396,18 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
chanelXMeterRslt?.CopyContentFrom(meterRslt);
if (iCH == 0)
{
CalculateMeterResults(chanelXMeterRslt, genesisSmart, tstRslt, genesisSmart.TimestampSecStartCh1,
genesisSmart.TimestampSecEndCh1, genesisSmart.VolumeLtrStartCh1, genesisSmart.VolumeLtrEndCh1);
CalculateMeterResults(chanelXMeterRslt, genesisSmart, tstRslt, genesisSmart.TimestampSecStartRawCh1,
genesisSmart.TimestampSecEndRawCh1, genesisSmart.VolumeLtrStartRawCh1, genesisSmart.VolumeLtrEndRawCh1);
}
else if (iCH == 1)
{
CalculateMeterResults(chanelXMeterRslt, genesisSmart, tstRslt, genesisSmart.TimestampSecStartCh2,
genesisSmart.TimestampSecEndCh2, genesisSmart.VolumeLtrStartCh2, genesisSmart.VolumeLtrEndCh2);
CalculateMeterResults(chanelXMeterRslt, genesisSmart, tstRslt, genesisSmart.TimestampSecStartRawCh2,
genesisSmart.TimestampSecEndRawCh2, genesisSmart.VolumeLtrStartRawCh2, genesisSmart.VolumeLtrEndRawCh2);
}
else if (iCH == 2)
{
CalculateMeterResults(chanelXMeterRslt, genesisSmart, tstRslt, genesisSmart.TimestampSecStartCh3,
genesisSmart.TimestampSecEndCh3, genesisSmart.VolumeLtrStartCh3, genesisSmart.VolumeLtrEndCh3);
CalculateMeterResults(chanelXMeterRslt, genesisSmart, tstRslt, genesisSmart.TimestampSecStartRawCh3,
genesisSmart.TimestampSecEndRawCh3, genesisSmart.VolumeLtrStartRawCh3, genesisSmart.VolumeLtrEndRawCh3);
}
if (!genesisSmart.EnableShowChanels)
@@ -0,0 +1,26 @@
///
/// Copyright (c) 2015-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.Generic;
using TBF.Rig.TestMethods.GenesisCommunication;
namespace TBF.Rig.TestMethods.GenesisFullCommunication
{
public class Factory : IComponentFactory
{
public string ClassName { get { return GetType().Namespace.Substring(8); } }
public IComponent DummyComponent() { return new TestMethod(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new TestMethod(cfg); }
public IComponentCfg DefaultConfig() { return new TestMethodCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(TestMethodCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,211 @@
///
/// Copyright (c) 2015-2022 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using Common;
using Config.Entities;
using TBF.Resources;
using TBF.Rig.Generic;
using TBF.Rig.TestMethods.iPerlCommunication;
namespace TBF.Rig.TestMethods.GenesisFullCommunication
{
public class GenesisCommunicationParams : TestParamsBase, IParamsProvider, ITestParams
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(GenesisCommunicationParams) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public string Activity
{
get { return base.Activity; }
set { base.Activity = value; }
}
/// Communication activity
public bool SimultWithPrevious;
public bool SimultWithNext;
public override void InitializeAll()
{
Activity = iPerlCommunicationForm.ReadConfigurationStr;
SimultWithPrevious = false;
SimultWithNext = false;
}
string[] paramNames = new string[]
{
Strings.Activity,
Strings.Simultaneous_with_previous_step,
Strings.Simultaneous_with_next_step,
};
public override string ParamName(int i) { return paramNames[i]; }
public override int ParamsCount() { return paramNames.Length; }
public override ICollection<string> ParamValues(int i)
{
if (i == 0)
{
var retVal = new List<string>();
retVal.Add(iPerlCommunicationForm.ReadConfigurationStr);
retVal.Add(iPerlCommunicationForm.ReadSerialNrStr);
retVal.Add(string.Format("{0} A0", iPerlCommunicationForm.SetTestModeStr));
retVal.Add(string.Format("{0} A4", iPerlCommunicationForm.SetTestModeStr));
retVal.Add(iPerlCommunicationForm.ReadCalibrationStr);
retVal.Add(iPerlCommunicationForm.ReadCalibrationV4Str);
retVal.Add(iPerlCommunicationForm.NormalizeCalibrationFactorStr);
retVal.Add(iPerlCommunicationForm.NormalizeCalibrationV4FactorsStr);
retVal.Add(iPerlCommunicationForm.GetDefaultQ2CorrectionsStr);
retVal.Add(iPerlCommunicationForm.ReadQ2CorrectionStr);
retVal.Add(iPerlCommunicationForm.ResetQ2CorrectionStr);
retVal.Add(iPerlCommunicationForm.WriteDefaultQ2CorrectionsStr);
retVal.Add(iPerlCommunicationForm.InitOrReadQ2CorrectionsStr);
retVal.Add(iPerlCommunicationForm.WriteCalibrationFactorStr);
retVal.Add(iPerlCommunicationForm.WriteCalibrationV4FactorsStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionAltStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionGreeceStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionRLStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionLRStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionIncl05Str);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionAltIncl05Str);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionPlusIncl05Str);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionPlusAltIncl05Str);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionGreeceIncl05Str);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionRLIncl05Str);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionLRIncl05Str);
retVal.Add(iPerlCommunicationSeq.Q2correctedFromCmd + "Qx");
retVal.Add(iPerlCommunicationSeq.StrictQ2ErrorCheckStr + "Qx");
retVal.Add(iPerlCommunicationSeq.Q2correctionCheckCmd);
retVal.Add(iPerlCommunicationSeq.IperlCheckCmd);
retVal.Add(iPerlCommunicationForm.UpdateBothQ2FactorsTestRLOnlyStr);
retVal.Add(iPerlCommunicationForm.UpdateBothQ2FactorsTestLROnlyStr);
retVal.Add(iPerlCommunicationForm.UpdateQ2CorrectionsStr);
retVal.Add(iPerlCommunicationForm.ConditnlUpdateQ2CorrectionsStr);
retVal.Add(iPerlCommunicationForm.ConditnlUpdateQ2CorrRLStr);
retVal.Add(iPerlCommunicationForm.ConditnlUpdateQ2CorrLRStr);
retVal.Add("Q2 corrected from Q2adj");
retVal.Add("Q2 correction check Q2bc Q2ac");
retVal.Add(iPerlCommunicationForm.SetActiveModeStr);
retVal.Add(iPerlCommunicationForm.SetIdleModeStr);
retVal.Add("---");
retVal.Add(iPerlCommunicationForm.Reset2HzCorrectionStr);
retVal.Add(iPerlCommunicationForm.Write2HzCorrectionStr);
retVal.Add(iPerlCommunicationForm.DewaReworkRLStr);
retVal.Add(iPerlCommunicationForm.DewaReworkLRStr);
retVal.Add(iPerlCommunicationForm.StartTestingSealedMetersStr);
retVal.Add(iPerlCommunicationForm.EndTestingSealedMetersStr);
retVal.Add(string.Format("{0} if enabled", iPerlCommunicationForm.ReadConfigurationStr));
retVal.Add(string.Format("{0} 80", iPerlCommunicationForm.SetTestModeStr));
retVal.Add("iPerl_check prevWorkStep direction q2factors");
for (iPerlCommunication.ConditionID id = iPerlCommunication.ConditionID.A; id < iPerlCommunication.ConditionID.Count; id++)
{
retVal.Add(string.Format(iPerlCommunication.SequenceConditionOp.ConditionNameFmt, id));
}
return retVal;
}
else
{
return new string[] { Strings.yes, Strings.no };
}
}
public override string ToString(int i)
{
switch (i)
{
case 0: return Activity;
case 1: return (SimultWithPrevious ? Strings.yes : Strings.no);
case 2: return (SimultWithNext ? Strings.yes : Strings.no);
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: Activity = strValue; return CfgUpdateFlags.None;
case 1: SimultWithPrevious = strValue.ToLower().Equals(Strings.yes.ToLower()); return CfgUpdateFlags.None;
case 2: SimultWithNext = strValue.ToLower().Equals(Strings.yes.ToLower()); return CfgUpdateFlags.None;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
switch (i)
{
case 0:
return true;
case 1:
case 2:
if (strValue.Equals(Strings.yes) || strValue.Equals(Strings.no)) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(GenesisCommunicationParams prms)
{
prms.Activity = this.Activity;
prms.SimultWithPrevious = this.SimultWithPrevious;
prms.SimultWithNext = this.SimultWithNext;
}
public IParamsProvider Clone()
{
GenesisCommunicationParams pars = new GenesisCommunicationParams();
CopyContentTo(pars);
return pars;
}
public override void UpdateFromDbEntity(ComponentTest dbEntity)
{
if (dbEntity == null) return;
try
{
GenesisCommunicationParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as GenesisCommunicationParams;
testParamsEntity = dbEntity;
componentName = dbEntity.CmpntName;
test = dbEntity.Test;
if (tmp != null) tmp.CopyContentTo(this);
}
catch
{
}
}
/// <summary>
/// Parameterless constructor initializes the parameters
/// </summary>
public GenesisCommunicationParams()
{
}
public GenesisCommunicationParams(bool initialize)
{
if (initialize) InitializeAll();
}
public GenesisCommunicationParams(ComponentTest testParamsEntity, string componentName, Test test)
{
this.testParamsEntity = testParamsEntity;
this.componentName = componentName;
this.test = test;
}
}
}
@@ -0,0 +1,962 @@
///
/// Copyright (c) 2015-2023 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Drawing;
using Common;
using Config.Entities;
using log4net;
using RestClient;
using Results.Entities;
using TBF.Resources;
using TBF.Rig.Generic;
using TBF.Rig.Sequences;
using TBF.Rig.TestMethods.iPerlCommunication;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
using TBF.UiBridge;
/// Point definition
namespace TBF.Rig.TestMethods.GenesisFullCommunication
{
public class GenesisCommunicationSeq : SequenceBase
{
private static readonly ILog log = LogManager.GetLogger(typeof(GenesisCommunicationSeq));
public const string Q2correctedFromCmd = "Q2 corrected from ";
public const string StrictQ2ErrorCheckStr = "Strict Q2 error check ";
public const string Q2correctionCheckCmd = "Q2 correction check ";
public const string IperlCheckCmd = "iPERL_check ";
public const string SimulateCmd = "simulate ";
System.Windows.Forms.Form modelessDlg;
///
delegate void IPerlCommFormDlgt(GenesisCommunicationSeq myRef, TestMethod method, Test test, GenesisCommunicationParams testParams);
///
void OpenIPerlCommForm(GenesisCommunicationSeq myRef, TestMethod method, Test test, GenesisCommunicationParams testParams)
{
//TODO solve this wia SmartCommunicationForm
myRef.modelessDlg = new SmartCommunicationForm(method, test, testParams);
myRef.modelessDlg.Show();
//myRef.modelessDlg = new iPerlCommunicationForm(method, test, testParams);
}
void CloseIPerlCommForm()
{
UiBridge.Bridge.OnCloseModelessForm(this, null);
modelessDlg = null;
}
/// <summary>
/// Flying start mass collection method sequence
/// </summary>
/// <param name="test">Test entity</param>
/// <returns>
/// Event.Done . . . . . . . OK
/// Event.UiCmdStop . . . . Stopped by the user using the on-screen button STOP
/// Event.OpArgumentError . Target flow is out of range
/// Event.Error . . . . . . Unspecified error
/// </returns>
public IList<Event> Execute(Test test, int repetitionNr, TestMethod method, ITestParams testParams)
{
TestMethodCfg cfg = method.Cfg as TestMethodCfg;
IList<Event> e; /// Events from currently running operations
checkUiOp = new Operations.CheckUIOp(true); /// Runs in more then one state
modelessDlg = null;
processDataLoggingOp = new TBF.Rig.Operations.ProcessDataLoggingOp(processDataLogger, this, false);
string cmd;
if (testParams.Activity.ToLower().Equals(cmd = iPerlCommunicationForm.GetDefaultQ2CorrectionsStr.ToLower()))
{
TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 });
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.FlowSetting));
/// Get 'wmType' from IperlHead procedure parameters
int wmType = 0;
#if IPERL
/*foreach (var wm in ProcessData.BatchRslts.Batch.WaterMeters)
{
if (wm != null && !wm.Disabled && wm.WMTypeId() > 0)
{
wmType = wm.WMTypeId();
break;
}
}*/
#endif
if (cfg.UseWebService)
{
IsQ2PreCorrectionCalculated = GetQ2PreCorrectionsOrBackups(cfg, wmType, out CalculatedQ2PreCorrectionLR, out CalculatedQ2PreCorrectionRL);
}
/// Generate test results
Results.Entities.TestRslt tstRslt = BatchRslts.GetTestRslt(test.Name, 0);
if (tstRslt != null)
{
tstRslt.StartTime = DateTime.Now;
tstRslt.TestDone = true;
foreach (var wm in BatchRslts.Batch.WaterMeters)
{
if (!wm.Disabled)
{
foreach(var mtr in wm.MeterTestRslts)
{
if (mtr.TestRslt == tstRslt)
{
mtr.Passed = !cfg.UseWebService || IsQ2PreCorrectionCalculated;
mtr.TestDone = true;
break;
}
}
}
}
}
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.Completed));
Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, ProcessData.BatchRslts.GetTestRslt(test.Name, 0)));
allResults.Info(TestResult2CsvLine(test.Name, 0)); /// Append the results to the CSV-file
return new List<Event> { Event.Done };
}
else if (testParams.Activity.ToLower().Contains(cmd = Q2correctedFromCmd.ToLower()))
{
TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 });
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.FlowSetting));
string[] args = testParams.Activity.Substring(cmd.Length).Split(new char[] { ' ' });
string fromTestName = (args.Length >= 1) ? args[0] : string.Empty;
bool isPlus = (args.Length >= 2) ? args[1].ToLower().Contains("plus") : false;
MakeQ2CorrectedFrom(test.Name, fromTestName, isPlus);
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.Completed));
Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, ProcessData.BatchRslts.GetTestRslt(test.Name, 0)));
allResults.Info(TestResult2CsvLine(test.Name, 0)); /// Append the results to the CSV-file
return new List<Event> { Event.Done };
}
else if (testParams.Activity.ToLower().Contains(cmd = StrictQ2ErrorCheckStr.ToLower()))
{
TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 });
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.FlowSetting));
string fromTestName = testParams.Activity.Substring(cmd.Length);
StrictQ2ErrorCheck(test.Name, fromTestName);
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.Completed));
Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, ProcessData.BatchRslts.GetTestRslt(test.Name, 0)));
allResults.Info(TestResult2CsvLine(test.Name, 0)); /// Append the results to the CSV-file
return new List<Event> { Event.Done };
}
else if (testParams.Activity.ToLower().Contains(cmd = Q2correctionCheckCmd.ToLower()))
{
TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 });
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.FlowSetting));
string[] testNames = testParams.Activity.Substring(cmd.Length).Split(new char[] { ' ' });
if (testNames.Length >= 2)
{
CheckQ2Correction(test.Name, testNames[0], testNames[1]);
}
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.Completed));
Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, ProcessData.BatchRslts.GetTestRslt(test.Name, 0)));
allResults.Info(TestResult2CsvLine(test.Name, 0)); /// Append the results to the CSV-file
return new List<Event> { Event.Done };
}
else if (testParams.Activity.ToLower().Contains(cmd = IperlCheckCmd.ToLower()))
{
TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 });
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.FlowSetting));
string[] args = testParams.Activity.Substring(cmd.Length).Split(new char[] { ' ' });
//int maxTestIndex = (ProcessData.BenchInfo is TBF.Rig.DataContainer.BenchInfo.Component)
// ? (ProcessData.BenchInfo as TBF.Rig.DataContainer.BenchInfo.Component).MaxTestIndex
// : int.MaxValue;
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(test.Name, 0);
if (tstRslt != null)
{
tstRslt.StartTime = DateTime.Now;
int wrongMetersCount = 0;
string message = string.Empty;
for (int i = 0; i < BatchRslts.WMPositionsCount; i++)
{
Results.Entities.WaterMeter wm = BatchRslts.Batch.WaterMeters[i];
Results.Entities.MeterTestRslt mtr = ProcessData.BatchRslts.GetMeterTestRslt(test.Name, i, CompoundMeterId.Single);
///// Reference to iPerl water meter or null:
//TestMethods.iPerlCommunication.iPerlHead.IperlHead iPerlHead = ((sensPath.RegisterReaders != null) && (i < sensPath.RegisterReaders.Length))
// ? (sensPath.RegisterReaders[i] as TestMethods.iPerlCommunication.iPerlHead.IperlHead)
// : null;
if ((wm != null) && (mtr != null))
{
int errorIndicators = 0;
bool anyErrorOfThisMeter = false;
foreach (var arg in args)
{
#if TURA_SPECIAL
if (arg.ToLower() == "q2factors")
{
if ((wm.ProdQ2CorrRL != wm.Q2CorrRL) || (wm.ProdQ2CorrLR != wm.Q2CorrLR))
{
anyErrorOfThisMeter = true;
message += string.Format("Q2 korekčné faktory vodomera {0} nesedia{1}", wm.WMPosition, Environment.NewLine);
errorIndicators |= (int)ErrorFlagMask.E26; /// Q2 correction factors not valid
}
}
#endif
if (arg.ToLower() == "direction")
{
//if (wm.Pruefindex > maxTestIndex)
//{
// anyErrorOfThisMeter = true;
// message += string.Format("Príliš veľa opakovaní testu vodomera {0}{1}", wm.WMPosition, Environment.NewLine);
// errorIndicators |= (int)ErrorFlagMask.E27; /// Wrong direction (positive/negative counting)
//}
}
if (arg.ToLower() == "prevworkstep")
{
if (wm.LastRecordIsNok)
{
wm.ErrorFlags |= (int)ErrorFlagMask.E28; /// Set E28
}
if ((wm.ErrorFlags & (int)ErrorFlagMask.E28) != 0)
{
anyErrorOfThisMeter = true;
message += string.Format("iPerl{0} : Predchádzajúci krok nebol zaznamenaný{1}", wm.WMPosition, Environment.NewLine);
errorIndicators |= (int)ErrorFlagMask.E28; /// Previous workstep missing or NOK (production tracing)
}
}
}
mtr.TestDone = true;
mtr.ErrorIndicators = errorIndicators;
///
if (anyErrorOfThisMeter)
{
/// This iPerl check did not pass
mtr.Passed = false;
wrongMetersCount++;
}
else
{
/// Check passed OK
mtr.Passed = true;
}
}
}
tstRslt.EndTime = DateTime.Now;
tstRslt.TestDone = true;
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.Completed));
Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, tstRslt));
allResults.Info(TestResult2CsvLine(test.Name, 0)); /// Append the results to the CSV-file
if (wrongMetersCount >= cfg.IperlCheckErrorsToStop)
{
State.Create("iPerlCommunicationSeq : Show check result")
.AddOperation(new Operations.LargeMessageBoxOp(message))
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
}
while (!e.Contains(Event.Continue) && !e.Contains(Event.Abort));
if (e.Contains(Event.Abort))
{
Bridge.OnError(this, string.Format("Niečo nie je v poriadku !"));
return new List<Event> { Event.UiCmdStop };
}
}
}
return new List<Event> { Event.Done };
}
else if (testParams.Activity.ToLower().Contains(cmd = SimulateCmd))
{
TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 });
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.JustStarted));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.FlowSetting));
if (testParams.Activity.ToLower().Contains("q3")) MakeSimulated(test, 1, 0, -0.5f);
else if (testParams.Activity.Substring(cmd.Length).ToLower() == "q2") MakeSimulated(test, 1, 0, 0.5f);
else if (testParams.Activity.Substring(cmd.Length).ToLower() == "q1") MakeSimulated(test, 1, 0, -5.1f);
else if (testParams.Activity.Substring(cmd.Length).ToLower() == "compound ok") MakeSimulatedCompound(test, 1, 0, 0.7f, 1.0f);
else if (testParams.Activity.Substring(cmd.Length).ToLower() == "compound nok") MakeSimulatedCompound(test, 1, 0, 4.7f, 0.9f);
else if (testParams.Activity.Substring(cmd.Length).ToLower() == "compound rise") MakeSimulatedCompound(test, 1, 0, 0.7f, 0.0f);
else if (testParams.Activity.Substring(cmd.Length).ToLower() == "compound fall") MakeSimulatedCompound(test, 1, 0, 0.7f, 0.9f);
else if (testParams.Activity.Substring(cmd.Length).ToLower() == "iperls")
{
string[] pcbNrs = new string[] { "831232435539", "831232435562", "831232435587",
"831232432141", "831232432497", "831232763641" };
TestRslt tstRslt = BatchRslts.GetTestRslt(test.Name, test.Part);
if (tstRslt != null)
{
Results.Utils.GetCounterStates(tstRslt, Program.LocalSettings.Counters);
/// Auxiliary results ... not required
/// Main results
tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName;
tstRslt.TestDone = true;
tstRslt.StartTime = tstRslt.Batch.StartTime;
tstRslt.EndTime = DateTime.Now;
tstRslt.FlowSetTime = 0;
tstRslt.MassOfEvapWater = 0;
tstRslt.TestTime = 1;
for (int i = 0; i < BatchRslts.Batch.WaterMeters.Count; i++)
{
MeterTestRslt meterRslt =
BatchRslts.GetMeterTestRslt(test.Name, i, CompoundMeterId.Single);
if (meterRslt != null)
{
meterRslt.WaterMeter.SerialNr = pcbNrs[i % pcbNrs.Length];
meterRslt.Passed = true;
meterRslt.TestDone = true;
}
//if (iperlHeads[i] != null)
//{
// iperlHeads[i].CommFailed = iperlHeads[i].Disabled = false;
// iperlHeads[i].SerialNr = pcbNrs[i % pcbNrs.Length];
//}
}
}
}
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Progress.Completed));
Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, ProcessData.BatchRslts.GetTestRslt(Common.Utils.GetTestName(test.Name, 1, 1), 0)));
allResults.Info(TestResult2CsvLine(test.Name, 0)); /// Append the results to the CSV-file
//------------------------------------------------
Bridge.OnActivity(this, testParams.Activity);
//------------------------------------------------
State.Create(string.Format("iPerlCommunicationSeq : {0}", testParams.Activity))
.AddOperation(checkUiOp)
.EnterState();
e = StateMachine.WaitRunDevsRunOps();
if (TestAndLogUiCmdStop(test, e))
{
return new List<Event> { Event.UiCmdStop };
}
}
else
{
///
/// Show the modeless dialog with error indication
///
Program.MainWnd.Invoke(new IPerlCommFormDlgt(OpenIPerlCommForm), new object[] { this, method, test, testParams });
//------------------------------------------------
Bridge.OnActivity(this, Strings.iPerl_Communication_in_progress);
//------------------------------------------------
bool stopPressed = false; /// true when STOP button pressed
bool completed = false;
State.Create("iPerlCommunicationSeq : Wait until the entry form is closed")
.AddOperation(checkUiOp)
.EnterState();
do {
e = StateMachine.WaitRunDevsRunOps();
stopPressed = TestAndLogUiCmdStop(test, e);
completed = (modelessDlg is GenericDevices.IHasCompleted)
&& (modelessDlg as GenericDevices.IHasCompleted).Completed;
}
while (!stopPressed && !completed);
if (stopPressed)
{
CloseIPerlCommForm();
return new List<Event> { Event.UiCmdStop };
}
else
{
TBF.UiBridge.Bridge.OnTestProgress(null, new TBF.UiBridge.TestProgressEventArgs(test.Name, Progress.Completed));
}
/// Test 'Quit'
modelessDlg = null; /// Modeless dialog is closed now
}
return new List<Event> { Event.Done };
}
/// <summary>
/// Read default Q2 correction factors from a REST service (= Web service).
/// </summary>
/// <param name="cfg">iPerlCommunication component configuration</param>
/// <param name="wmType">Water meter type (WZ Typ)</param>
/// <param name="q2PreCorrectionLR">Default Q2 correction LR</param>
/// <param name="q2PreCorrectionRL">Default Q2 correction RL</param>
/// <returns>true when successful</returns>
static bool ReadCorrectionsFromWebService(TestMethodCfg cfg, int wmType, out int q2PreCorrectionLR, out int q2PreCorrectionRL)
{
if (wmType == 0)
{
/// No REST service call when wmType == 0, factors are 0
q2PreCorrectionLR = 0;
q2PreCorrectionRL = 0;
return true;
}
try
{
GetQ2PreCorrectionClient client = new GetQ2PreCorrectionClient(cfg.BaseUrl);
client.GetToken("ReadUser", "sensus", "https://deluh1web03.world.fluidtechnology.net/SensusCore/api/v1/Locations/1/Login2").Wait();
Q2PreCorrection response = client.GetQ2Correction(string.Format(cfg.RelativeUrl, wmType)).Result;
if (response != null && response.AreDataCalculated)
{
q2PreCorrectionLR = response.CorrLR;
q2PreCorrectionRL = response.CorrRL;
log.WarnFormat("Q2 corrections from a REST client for WM Type = {0} are: LR = {1}, RL = {2}", wmType, q2PreCorrectionLR, q2PreCorrectionRL);
return true;
}
else
{
log.ErrorFormat("Failed to obtain Q2 corrections from a REST client for WM Type = {0}", wmType);
q2PreCorrectionLR = 0;
q2PreCorrectionRL = 0;
return false;
}
}
catch (Exception exc)
{
log.ErrorFormat("Failed to obtain Q2 corrections from a REST client for WM Type = {0}: {1}", wmType, exc.Message);
q2PreCorrectionLR = 0;
q2PreCorrectionRL = 0;
return false;
}
}
/// <summary>
/// Obtain Q2 correction factors from a REST service or from local settings (stored backup values)
/// </summary>
/// <param name="cfg">iPerlCommunication component configuration</param>
/// <param name="wmType">Water meter type (WZ Typ)</param>
/// <param name="q2PreCorrectionLR">Default Q2 correction LR</param>
/// <param name="q2PreCorrectionRL">Default Q2 correction RL</param>
/// <returns>true when successful</returns>
public static bool GetQ2PreCorrectionsOrBackups(TestMethodCfg cfg, int wmType, out int q2PreCorrectionLR, out int q2PreCorrectionRL)
{
/// Get Q2 pre-correction values from REST service
bool restOK = ReadCorrectionsFromWebService(cfg, wmType, out q2PreCorrectionLR, out q2PreCorrectionRL);
/// Store / load Q2 pre-correction values
Point storedValue;
if (restOK)
{
/// Q2 pre-correction values were successfully obtained from a REST service for the specified wmType
if (!Program.LocalSettings.Q2PreCorrections.TryGetValue(wmType, out storedValue))
{
/// No Q2 pre-correction values in the dictionary for the specified wmType => save them
Program.LocalSettings.Q2PreCorrections.Add(wmType, new Point(q2PreCorrectionLR, q2PreCorrectionRL));
log.WarnFormat("Q2 corrections added to dictionary for WM Type = {0}: LR = {1}, RL = {2}", wmType, q2PreCorrectionLR, q2PreCorrectionRL);
}
else if (storedValue.X != q2PreCorrectionLR || storedValue.Y != q2PreCorrectionRL)
{
/// Different Q2 pre-correction values in the dictionary for the specified wmType => overwrite them with ones from the REST service
Program.LocalSettings.Q2PreCorrections[wmType] = new Point(q2PreCorrectionLR, q2PreCorrectionRL);
log.WarnFormat("Q2 corrections modified in dictionary for WM Type = {0}: LR = {1}, RL = {2}", wmType, q2PreCorrectionLR, q2PreCorrectionRL);
}
else
{
/// Q2 pre-correction values in the dictionary are the same and were not changed
log.WarnFormat("Q2 corrections in dictionary for WM Type = {0} are the same and were not changed", wmType, q2PreCorrectionLR, q2PreCorrectionRL);
}
}
else
{
/// No Q2 pre-correction values from a REST service => read the dictionary
if (Program.LocalSettings.Q2PreCorrections.TryGetValue(wmType, out storedValue))
{
/// Q2 pre-correction values successfully read from the dictionary
q2PreCorrectionLR = storedValue.X;
q2PreCorrectionRL = storedValue.Y;
log.WarnFormat("Q2 corrections loaded from dictionary for WM Type = {0}: LR = {1}, RL = {2}", wmType, q2PreCorrectionLR, q2PreCorrectionRL);
}
else
{
/// Q2 pre-correction values not found in the dictionary => use zeros
q2PreCorrectionLR = 0;
q2PreCorrectionRL = 0;
log.ErrorFormat("Q2 corrections not found in the dictionary for WM Type = {0}, using zeros", wmType, q2PreCorrectionLR, q2PreCorrectionRL);
/// Everything failed => using zero values
return false;
}
}
/// Q2 pre-corections were obtained from REST service or stored backup values were used
return true;
}
/// <summary>
/// Virtually apply Q2 correction to a test used for the correction calculation.
/// </summary>
/// <param name="testName">This test name</param>
/// <param name="oriTestRslt">Name of Q2 test done before Q2 correction (Q2adj)</param>
/// <remarks>Assuming this test does not have multiple parts (part = 0)</remarks>
void MakeQ2CorrectedFrom(string testName, string oriTestName, bool isPlus = false)
{
Results.Entities.TestRslt oriTestRslt = ProcessData.BatchRslts.GetTestRslt(oriTestName, 0);
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(testName, 0);
if (oriTestRslt == null || tstRslt == null) return;
tstRslt.Components = oriTestRslt.Components;
/// Auxiliary results, as in SequenceBase.UpdateTemoPressDensAmb()
tstRslt.AmbTempMean = oriTestRslt.AmbTempMean;
tstRslt.AmbTempStart = oriTestRslt.AmbTempStart;
tstRslt.AmbTempEnd = oriTestRslt.AmbTempEnd;
tstRslt.AmbTempMin = oriTestRslt.AmbTempMin;
tstRslt.AmbTempMax = oriTestRslt.AmbTempMax;
tstRslt.AmbPressMean = oriTestRslt.AmbPressMean;
tstRslt.AmbPressStart = oriTestRslt.AmbPressStart;
tstRslt.AmbPressEnd = oriTestRslt.AmbPressEnd;
tstRslt.AmbPressMin = oriTestRslt.AmbPressMin;
tstRslt.AmbPressMax = oriTestRslt.AmbPressMax;
tstRslt.AmbHumiMean = oriTestRslt.AmbHumiMean;
tstRslt.AmbHumiStart = oriTestRslt.AmbHumiStart;
tstRslt.AmbHumiEnd = oriTestRslt.AmbHumiEnd;
tstRslt.AmbHumiMin = oriTestRslt.AmbHumiMin;
tstRslt.AmbHumiMax = oriTestRslt.AmbHumiMax;
tstRslt.PressUpMean = oriTestRslt.PressUpMean;
tstRslt.PressUpStart = oriTestRslt.PressUpStart;
tstRslt.PressUpEnd = oriTestRslt.PressUpEnd;
tstRslt.PressUpMin = oriTestRslt.PressUpMin;
tstRslt.PressUpMax = oriTestRslt.PressUpMax;
tstRslt.PressDownMean = oriTestRslt.PressDownMean;
tstRslt.PressDownStart = oriTestRslt.PressDownStart;
tstRslt.PressDownEnd = oriTestRslt.PressDownEnd;
tstRslt.PressDownMin = oriTestRslt.PressDownMin;
tstRslt.PressDownMax = oriTestRslt.PressDownMax;
tstRslt.PressDeltaMean = oriTestRslt.PressDeltaMean;
tstRslt.PressDeltaStart = oriTestRslt.PressDeltaStart;
tstRslt.PressDeltaEnd = oriTestRslt.PressDeltaEnd;
tstRslt.PressDeltaMin = oriTestRslt.PressDeltaMin;
tstRslt.PressDeltaMax = oriTestRslt.PressDeltaMax;
tstRslt.ConductMean = oriTestRslt.ConductMean;
tstRslt.ConductStart = oriTestRslt.ConductStart;
tstRslt.ConductEnd = oriTestRslt.ConductEnd;
tstRslt.ConductMin = oriTestRslt.ConductMin;
tstRslt.ConductMax = oriTestRslt.ConductMax;
tstRslt.TempUpMean = oriTestRslt.TempUpMean;
tstRslt.TempUpStart = oriTestRslt.TempUpStart;
tstRslt.TempUpEnd = oriTestRslt.TempUpEnd;
tstRslt.TempUpMin = oriTestRslt.TempUpMin;
tstRslt.TempUpMax = oriTestRslt.TempUpMax;
tstRslt.TempDownMean = oriTestRslt.TempDownMean;
tstRslt.TempDownStart = oriTestRslt.TempDownStart;
tstRslt.TempDownEnd = oriTestRslt.TempDownEnd;
tstRslt.TempDownMin = oriTestRslt.TempDownMin;
tstRslt.TempDownMax = oriTestRslt.TempDownMax;
tstRslt.TempDivMean = oriTestRslt.TempDivMean;
tstRslt.TempDivStart = oriTestRslt.TempDivStart;
tstRslt.TempDivEnd = oriTestRslt.TempDivEnd;
tstRslt.TempDivMin = oriTestRslt.TempDivMin;
tstRslt.TempDivMax = oriTestRslt.TempDivMax;
tstRslt.DensityIn = oriTestRslt.DensityIn;
tstRslt.DensityLine = oriTestRslt.DensityLine;
tstRslt.DensityDiv = oriTestRslt.DensityDiv;
tstRslt.StartTime = oriTestRslt.StartTime;
tstRslt.EndTime = oriTestRslt.EndTime;
tstRslt.FlowSetTime = oriTestRslt.FlowSetTime;
tstRslt.TestTime = oriTestRslt.TestTime;
tstRslt.PulsesMaster = oriTestRslt.PulsesMaster;
tstRslt.ConstMasterRaw = oriTestRslt.ConstMasterRaw;
tstRslt.ConstMaster = oriTestRslt.ConstMaster;
tstRslt.MassStartRaw = oriTestRslt.MassStartRaw;
tstRslt.MassStart = oriTestRslt.MassStart;
tstRslt.MassEndRaw = oriTestRslt.MassEndRaw;
tstRslt.MassEnd = oriTestRslt.MassEnd;
tstRslt.MassOfEvapWater = oriTestRslt.MassOfEvapWater;
//tstRslt.FlowMass = oriTestRslt.FlowMass;
//tstRslt.FlowVolume = oriTestRslt.FlowVolume;
tstRslt.VolumeCTV = oriTestRslt.VolumeCTV;
tstRslt.VolumeMaster = oriTestRslt.VolumeMaster;
tstRslt.ErrorMaster = oriTestRslt.ErrorMaster;
tstRslt.FlowMean = oriTestRslt.FlowMean;
tstRslt.FlowMin = oriTestRslt.FlowMin;
tstRslt.FlowMax = oriTestRslt.FlowMax;
tstRslt.Custom1 = oriTestRslt.Custom1;
tstRslt.Custom2 = oriTestRslt.Custom2;
tstRslt.Custom3 = oriTestRslt.Custom3;
tstRslt.Custom4 = oriTestRslt.Custom4;
tstRslt.Custom5 = oriTestRslt.Custom5;
tstRslt.Custom6 = oriTestRslt.Custom6;
tstRslt.Custom7 = oriTestRslt.Custom7;
tstRslt.Custom8 = oriTestRslt.Custom8;
for (int i = 0; i < ProcessData.BatchRslts.WMPositionsCount; i++)
{
// Fix for CS7036: Added the missing 'meterId' argument to the GetMeterTestRslt method call.
var q3mtr = ProcessData.BatchRslts.GetMeterTestRslt("Q3", i, CompoundMeterId.SingleOrCompound);
double q3error = (q3mtr != null) ? q3mtr.Error : 0;
Results.Entities.MeterTestRslt oriMeterRslt = ProcessData.BatchRslts.GetMeterTestRslt(oriTestName, i, CompoundMeterId.SingleOrCompound);
Results.Entities.MeterTestRslt meterRslt = ProcessData.BatchRslts.GetMeterTestRslt(testName, i, CompoundMeterId.SingleOrCompound);
/// Reference to iPerl water meter or null:
TestMethods.iPerlCommunication.iPerlHead.IperlHead iPerl = ((sensPath != null) && (sensPath.RegisterReaders != null) && (i < sensPath.RegisterReaders.Length))
? (sensPath.RegisterReaders[i] as TestMethods.iPerlCommunication.iPerlHead.IperlHead)
: null;
if (iPerl != null && meterRslt != null && oriMeterRslt != null)
{
#if ORACLE_DB
meterRslt.ErrorBC = oriMeterRslt.Error;
#endif
meterRslt.PulsesMeter = oriMeterRslt.PulsesMeter;
meterRslt.PulsesMaster = oriMeterRslt.PulsesMaster;
meterRslt.PulsesPerLiter = oriMeterRslt.PulsesPerLiter;
meterRslt.VolumeRef = oriMeterRslt.VolumeRef;
meterRslt.TestTime = oriMeterRslt.TestTime;
if (q3error * oriMeterRslt.Error < 0)
{
/// iPerl with Q2 correction => generate an artificial error equal to +1/10 of the original one (relative to Q2 target error)
meterRslt.Error = 0.1 * oriMeterRslt.Error;
}
else
{
/// iPerl with Q2 correction => generate an artificial error equal to -1/10 of the original one (relative to Q2 target error)
meterRslt.Error = - 0.1 * oriMeterRslt.Error;
}
meterRslt.VolumeMeter = meterRslt.VolumeRef * (100.0 + meterRslt.Error) / 100.0;
double signature = (oriMeterRslt.VolumeEnd > oriMeterRslt.VolumeStart) ? (+1) : (-1);
meterRslt.VolumeStart = oriMeterRslt.VolumeStart;
meterRslt.VolumeEnd = meterRslt.VolumeStart + signature * meterRslt.VolumeMeter;
meterRslt.Passed = (meterRslt.Error >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin()
&& meterRslt.Error <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin());
meterRslt.TestDone = true;
tstRslt.TestDone = true;
}
}
}
/// <summary>
/// Evaluate a given Q2 test result agains stricter error limits when Oruefindex == 1.
/// </summary>
/// <param name="testName">This test name</param>
/// <param name="oriTestRslt">Name of Q2 test done before Q2 correction (Q2adj)</param>
/// <remarks>Assuming this test does not have multiple parts (part = 0)</remarks>
void StrictQ2ErrorCheck(string testName, string oriTestName)
{
Results.Entities.TestRslt oriTestRslt = ProcessData.BatchRslts.GetTestRslt(oriTestName, 0);
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(testName, 0);
if (oriTestRslt == null || tstRslt == null) return;
tstRslt.Components = oriTestRslt.Components;
/// Auxiliary results, as in SequenceBase.UpdateTemoPressDensAmb()
tstRslt.AmbTempMean = oriTestRslt.AmbTempMean;
tstRslt.AmbTempStart = oriTestRslt.AmbTempStart;
tstRslt.AmbTempEnd = oriTestRslt.AmbTempEnd;
tstRslt.AmbTempMin = oriTestRslt.AmbTempMin;
tstRslt.AmbTempMax = oriTestRslt.AmbTempMax;
tstRslt.AmbPressMean = oriTestRslt.AmbPressMean;
tstRslt.AmbPressStart = oriTestRslt.AmbPressStart;
tstRslt.AmbPressEnd = oriTestRslt.AmbPressEnd;
tstRslt.AmbPressMin = oriTestRslt.AmbPressMin;
tstRslt.AmbPressMax = oriTestRslt.AmbPressMax;
tstRslt.AmbHumiMean = oriTestRslt.AmbHumiMean;
tstRslt.AmbHumiStart = oriTestRslt.AmbHumiStart;
tstRslt.AmbHumiEnd = oriTestRslt.AmbHumiEnd;
tstRslt.AmbHumiMin = oriTestRslt.AmbHumiMin;
tstRslt.AmbHumiMax = oriTestRslt.AmbHumiMax;
tstRslt.PressUpMean = oriTestRslt.PressUpMean;
tstRslt.PressUpStart = oriTestRslt.PressUpStart;
tstRslt.PressUpEnd = oriTestRslt.PressUpEnd;
tstRslt.PressUpMin = oriTestRslt.PressUpMin;
tstRslt.PressUpMax = oriTestRslt.PressUpMax;
tstRslt.PressDownMean = oriTestRslt.PressDownMean;
tstRslt.PressDownStart = oriTestRslt.PressDownStart;
tstRslt.PressDownEnd = oriTestRslt.PressDownEnd;
tstRslt.PressDownMin = oriTestRslt.PressDownMin;
tstRslt.PressDownMax = oriTestRslt.PressDownMax;
tstRslt.PressDeltaMean = oriTestRslt.PressDeltaMean;
tstRslt.PressDeltaStart = oriTestRslt.PressDeltaStart;
tstRslt.PressDeltaEnd = oriTestRslt.PressDeltaEnd;
tstRslt.PressDeltaMin = oriTestRslt.PressDeltaMin;
tstRslt.PressDeltaMax = oriTestRslt.PressDeltaMax;
tstRslt.ConductMean = oriTestRslt.ConductMean;
tstRslt.ConductStart = oriTestRslt.ConductStart;
tstRslt.ConductEnd = oriTestRslt.ConductEnd;
tstRslt.ConductMin = oriTestRslt.ConductMin;
tstRslt.ConductMax = oriTestRslt.ConductMax;
tstRslt.TempUpMean = oriTestRslt.TempUpMean;
tstRslt.TempUpStart = oriTestRslt.TempUpStart;
tstRslt.TempUpEnd = oriTestRslt.TempUpEnd;
tstRslt.TempUpMin = oriTestRslt.TempUpMin;
tstRslt.TempUpMax = oriTestRslt.TempUpMax;
tstRslt.TempDownMean = oriTestRslt.TempDownMean;
tstRslt.TempDownStart = oriTestRslt.TempDownStart;
tstRslt.TempDownEnd = oriTestRslt.TempDownEnd;
tstRslt.TempDownMin = oriTestRslt.TempDownMin;
tstRslt.TempDownMax = oriTestRslt.TempDownMax;
tstRslt.TempDivMean = oriTestRslt.TempDivMean;
tstRslt.TempDivStart = oriTestRslt.TempDivStart;
tstRslt.TempDivEnd = oriTestRslt.TempDivEnd;
tstRslt.TempDivMin = oriTestRslt.TempDivMin;
tstRslt.TempDivMax = oriTestRslt.TempDivMax;
tstRslt.DensityIn = oriTestRslt.DensityIn;
tstRslt.DensityLine = oriTestRslt.DensityLine;
tstRslt.DensityDiv = oriTestRslt.DensityDiv;
tstRslt.StartTime = oriTestRslt.StartTime;
tstRslt.EndTime = oriTestRslt.EndTime;
tstRslt.FlowSetTime = oriTestRslt.FlowSetTime;
tstRslt.TestTime = oriTestRslt.TestTime;
tstRslt.PulsesMaster = oriTestRslt.PulsesMaster;
tstRslt.ConstMasterRaw = oriTestRslt.ConstMasterRaw;
tstRslt.ConstMaster = oriTestRslt.ConstMaster;
tstRslt.MassStartRaw = oriTestRslt.MassStartRaw;
tstRslt.MassStart = oriTestRslt.MassStart;
tstRslt.MassEndRaw = oriTestRslt.MassEndRaw;
tstRslt.MassEnd = oriTestRslt.MassEnd;
tstRslt.MassOfEvapWater = oriTestRslt.MassOfEvapWater;
//tstRslt.FlowMass = oriTestRslt.FlowMass;
//tstRslt.FlowVolume = oriTestRslt.FlowVolume;
tstRslt.VolumeCTV = oriTestRslt.VolumeCTV;
tstRslt.VolumeMaster = oriTestRslt.VolumeMaster;
tstRslt.ErrorMaster = oriTestRslt.ErrorMaster;
tstRslt.FlowMean = oriTestRslt.FlowMean;
tstRslt.FlowMin = oriTestRslt.FlowMin;
tstRslt.FlowMax = oriTestRslt.FlowMax;
tstRslt.Custom1 = oriTestRslt.Custom1;
tstRslt.Custom2 = oriTestRslt.Custom2;
tstRslt.Custom3 = oriTestRslt.Custom3;
tstRslt.Custom4 = oriTestRslt.Custom4;
tstRslt.Custom5 = oriTestRslt.Custom5;
tstRslt.Custom6 = oriTestRslt.Custom6;
tstRslt.Custom7 = oriTestRslt.Custom7;
tstRslt.Custom8 = oriTestRslt.Custom8;
for (int i = 0; i < ProcessData.BatchRslts.WMPositionsCount; i++)
{
Results.Entities.MeterTestRslt oriMeterRslt = ProcessData.BatchRslts.GetMeterTestRslt(oriTestName, i, CompoundMeterId.Single);
Results.Entities.MeterTestRslt meterRslt = ProcessData.BatchRslts.GetMeterTestRslt(testName, i, CompoundMeterId.Single);
/// Reference to iPerl water meter or null:
TestMethods.iPerlCommunication.iPerlHead.IperlHead iPerl = ((sensPath != null) && (sensPath.RegisterReaders != null) && (i < sensPath.RegisterReaders.Length))
? (sensPath.RegisterReaders[i] as TestMethods.iPerlCommunication.iPerlHead.IperlHead)
: null;
if (meterRslt != null && oriMeterRslt != null)
{
#if ORACLE_DB
meterRslt.ErrorBC = oriMeterRslt.Error;
#endif
meterRslt.PulsesMeter = oriMeterRslt.PulsesMeter;
meterRslt.PulsesMaster = oriMeterRslt.PulsesMaster;
meterRslt.PulsesPerLiter = oriMeterRslt.PulsesPerLiter;
meterRslt.VolumeRef = oriMeterRslt.VolumeRef;
meterRslt.TestTime = oriMeterRslt.TestTime;
if (iPerl != null && ProcessData.BatchRslts.Batch.WaterMeters[i] != null &&
!ProcessData.BatchRslts.Batch.WaterMeters[i].Disabled)
{
/// Either no iPerl head or no Q2 correction
meterRslt.Error = oriMeterRslt.Error;
meterRslt.VolumeMeter = oriMeterRslt.VolumeMeter;
meterRslt.VolumeStart = oriMeterRslt.VolumeStart;
meterRslt.VolumeEnd = oriMeterRslt.VolumeEnd;
#if ORACLE_DB
if ((ProcessData.BatchRslts.Batch.WaterMeters[i].Pruefindex % 100) == 1)
{
meterRslt.Passed = (oriMeterRslt.Error >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin()
&& oriMeterRslt.Error <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin());
}
else
#endif
{
meterRslt.Passed = oriMeterRslt.Passed;
}
meterRslt.TestDone = true;
tstRslt.TestDone = true;
}
}
}
}
/// <summary>
/// Check results of 2 tests: before Q2 correction and after Q2 correction.
/// Evaluate whether Q2 correction works OK.
/// </summary>
/// <param name="testName">This test name</param>
/// <param name="testNameQ2bc">Name of Q2 test done before correction</param>
/// <param name="testNameQ2ac">Name of Q2 test done after correction</param>
/// <remarks>Assuming these tests do not have multiple parts (part = 0)</remarks>
void CheckQ2Correction(string testName, string testNameQ2bc, string testNameQ2ac)
{
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(testName, 0);
Results.Entities.TestRslt testRsltQ2bc = ProcessData.BatchRslts.GetTestRslt(testNameQ2bc, 0);
Results.Entities.TestRslt testRsltQ2ac = ProcessData.BatchRslts.GetTestRslt(testNameQ2ac, 0);
if ((tstRslt == null) || (testRsltQ2bc == null) || (testRsltQ2ac == null)) return;
tstRslt.Components = testRsltQ2ac.Components;
/// Auxiliary results, as in SequenceBase.UpdateTemoPressDensAmb()
tstRslt.AmbTempMean = testRsltQ2ac.AmbTempMean;
tstRslt.AmbTempStart = testRsltQ2ac.AmbTempStart;
tstRslt.AmbTempEnd = testRsltQ2ac.AmbTempEnd;
tstRslt.AmbTempMin = testRsltQ2ac.AmbTempMin;
tstRslt.AmbTempMax = testRsltQ2ac.AmbTempMax;
tstRslt.AmbPressMean = testRsltQ2ac.AmbPressMean;
tstRslt.AmbPressStart = testRsltQ2ac.AmbPressStart;
tstRslt.AmbPressEnd = testRsltQ2ac.AmbPressEnd;
tstRslt.AmbPressMin = testRsltQ2ac.AmbPressMin;
tstRslt.AmbPressMax = testRsltQ2ac.AmbPressMax;
tstRslt.AmbHumiMean = testRsltQ2ac.AmbHumiMean;
tstRslt.AmbHumiStart = testRsltQ2ac.AmbHumiStart;
tstRslt.AmbHumiEnd = testRsltQ2ac.AmbHumiEnd;
tstRslt.AmbHumiMin = testRsltQ2ac.AmbHumiMin;
tstRslt.AmbHumiMax = testRsltQ2ac.AmbHumiMax;
tstRslt.PressUpMean = testRsltQ2ac.PressUpMean;
tstRslt.PressUpStart = testRsltQ2ac.PressUpStart;
tstRslt.PressUpEnd = testRsltQ2ac.PressUpEnd;
tstRslt.PressUpMin = testRsltQ2ac.PressUpMin;
tstRslt.PressUpMax = testRsltQ2ac.PressUpMax;
tstRslt.PressDownMean = testRsltQ2ac.PressDownMean;
tstRslt.PressDownStart = testRsltQ2ac.PressDownStart;
tstRslt.PressDownEnd = testRsltQ2ac.PressDownEnd;
tstRslt.PressDownMin = testRsltQ2ac.PressDownMin;
tstRslt.PressDownMax = testRsltQ2ac.PressDownMax;
tstRslt.PressDeltaMean = testRsltQ2ac.PressDeltaMean;
tstRslt.PressDeltaStart = testRsltQ2ac.PressDeltaStart;
tstRslt.PressDeltaEnd = testRsltQ2ac.PressDeltaEnd;
tstRslt.PressDeltaMin = testRsltQ2ac.PressDeltaMin;
tstRslt.PressDeltaMax = testRsltQ2ac.PressDeltaMax;
tstRslt.ConductMean = testRsltQ2ac.ConductMean;
tstRslt.ConductStart = testRsltQ2ac.ConductStart;
tstRslt.ConductEnd = testRsltQ2ac.ConductEnd;
tstRslt.ConductMin = testRsltQ2ac.ConductMin;
tstRslt.ConductMax = testRsltQ2ac.ConductMax;
tstRslt.TempUpMean = testRsltQ2ac.TempUpMean;
tstRslt.TempUpStart = testRsltQ2ac.TempUpStart;
tstRslt.TempUpEnd = testRsltQ2ac.TempUpEnd;
tstRslt.TempUpMin = testRsltQ2ac.TempUpMin;
tstRslt.TempUpMax = testRsltQ2ac.TempUpMax;
tstRslt.TempDownMean = testRsltQ2ac.TempDownMean;
tstRslt.TempDownStart = testRsltQ2ac.TempDownStart;
tstRslt.TempDownEnd = testRsltQ2ac.TempDownEnd;
tstRslt.TempDownMin = testRsltQ2ac.TempDownMin;
tstRslt.TempDownMax = testRsltQ2ac.TempDownMax;
tstRslt.TempDivMean = testRsltQ2ac.TempDivMean;
tstRslt.TempDivStart = testRsltQ2ac.TempDivStart;
tstRslt.TempDivEnd = testRsltQ2ac.TempDivEnd;
tstRslt.TempDivMin = testRsltQ2ac.TempDivMin;
tstRslt.TempDivMax = testRsltQ2ac.TempDivMax;
tstRslt.DensityIn = testRsltQ2ac.DensityIn;
tstRslt.DensityLine = testRsltQ2ac.DensityLine;
tstRslt.DensityDiv = testRsltQ2ac.DensityDiv;
tstRslt.StartTime = testRsltQ2ac.StartTime;
tstRslt.EndTime = testRsltQ2ac.EndTime;
tstRslt.FlowSetTime = testRsltQ2ac.FlowSetTime;
tstRslt.TestTime = testRsltQ2ac.TestTime;
tstRslt.PulsesMaster = testRsltQ2ac.PulsesMaster;
tstRslt.ConstMasterRaw = testRsltQ2ac.ConstMasterRaw;
tstRslt.ConstMaster = testRsltQ2ac.ConstMaster;
tstRslt.MassStartRaw = testRsltQ2ac.MassStartRaw;
tstRslt.MassStart = testRsltQ2ac.MassStart;
tstRslt.MassEndRaw = testRsltQ2ac.MassEndRaw;
tstRslt.MassEnd = testRsltQ2ac.MassEnd;
tstRslt.MassOfEvapWater = testRsltQ2ac.MassOfEvapWater;
//tstRslt.FlowMass = testRsltQ2ac.FlowMass;
//tstRslt.FlowVolume = testRsltQ2ac.FlowVolume;
tstRslt.VolumeCTV = testRsltQ2ac.VolumeCTV;
tstRslt.VolumeMaster = testRsltQ2ac.VolumeMaster;
tstRslt.ErrorMaster = testRsltQ2ac.ErrorMaster;
tstRslt.FlowMean = testRsltQ2ac.FlowMean;
tstRslt.FlowMin = testRsltQ2ac.FlowMin;
tstRslt.FlowMax = testRsltQ2ac.FlowMax;
tstRslt.Custom1 = testRsltQ2ac.Custom1;
tstRslt.Custom2 = testRsltQ2ac.Custom2;
tstRslt.Custom3 = testRsltQ2ac.Custom3;
tstRslt.Custom4 = testRsltQ2ac.Custom4;
tstRslt.Custom5 = testRsltQ2ac.Custom5;
tstRslt.Custom6 = testRsltQ2ac.Custom6;
tstRslt.Custom7 = testRsltQ2ac.Custom7;
tstRslt.Custom8 = testRsltQ2ac.Custom8;
for (int i = 0; i < ProcessData.BatchRslts.WMPositionsCount; i++)
{
Results.Entities.MeterTestRslt meterRslt = ProcessData.BatchRslts.GetMeterTestRslt(testName, i, CompoundMeterId.Single);
Results.Entities.MeterTestRslt meterRsltQ2bc = ProcessData.BatchRslts.GetMeterTestRslt(testNameQ2bc, i, CompoundMeterId.Single);
Results.Entities.MeterTestRslt meterRsltQ2ac = ProcessData.BatchRslts.GetMeterTestRslt(testNameQ2ac, i, CompoundMeterId.Single);
if ((meterRslt != null) && (meterRsltQ2bc != null) && (meterRsltQ2ac != null))
{
meterRslt.PulsesMeter = meterRsltQ2ac.PulsesMeter;
meterRslt.PulsesMaster = meterRsltQ2ac.PulsesMaster;
meterRslt.PulsesPerLiter = meterRsltQ2ac.PulsesPerLiter;
meterRslt.VolumeRef = meterRsltQ2ac.VolumeRef;
meterRslt.TestTime = meterRsltQ2ac.TestTime;
meterRslt.VolumeStart = meterRsltQ2ac.VolumeStart;
meterRslt.VolumeEnd = meterRsltQ2ac.VolumeEnd;
meterRslt.VolumeMeter = meterRsltQ2ac.VolumeMeter;
meterRslt.Error = meterRsltQ2ac.Error;
meterRslt.TestDone = meterRsltQ2ac.TestDone;
tstRslt.TestDone = true;
if (((meterRsltQ2bc.Error < -0.51) && (meterRsltQ2ac.Error < meterRsltQ2bc.Error)) ||
((meterRsltQ2bc.Error > +0.51) && (meterRsltQ2ac.Error > meterRsltQ2bc.Error)))
{
meterRslt.Passed = false; /// Q2 correction check failed
}
else
{
meterRslt.Passed = true; /// Q2 correction check passed
}
}
}
}
}
}
@@ -0,0 +1,43 @@
///
/// Copyright (c) 2022 Sensus Slovensko a.s.
///
namespace TBF.Rig.TestMethods.GenesisFullCommunication
{
public enum ConditionID
{
A,
B,
C,
Count,
}
public class SequenceConditionOp : IOperation
{
public const string ConditionNameFmt = "iPERL communication milestone {0}";
ConditionID id;
TestMethod testMethodComponent;
public SequenceConditionOp(TestMethod testMethodComponent, ConditionID id)
{
this.testMethodComponent = testMethodComponent;
this.id = id;
}
public void Start() { }
public Event Run()
{
bool conditionMet = testMethodComponent.IperlCommMilestone[(int)id];
return conditionMet ? Event.ConditionMet : Event.ConditionNotMet;
}
public void Stop() { }
public override string ToString()
{
return string.Format(ConditionNameFmt, id);
}
}
}
@@ -0,0 +1,181 @@
///
/// Copyright (c) 2015-2022 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using Common;
using Config.Entities;
using log4net;
using TBF.Rig.GenericDevices;
using TBF.Rig.Sequences;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
using TBF.UiBridge;
namespace TBF.Rig.TestMethods.GenesisFullCommunication
{
public class TestMethod : SmartComponentBase, ISimultTestMethod, ISequenceCondition, ISessionDataMngmnt, ITestMethodSmart
{
private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod));
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
public FlowType MethodFlowType => FlowType.volume;
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; }
public bool DoTransitions() { return false; }
public bool SimultWithPrevious { get { return testMethodCfg.TestParams.SimultWithPrevious; } }
public bool SimultWithNext { get { return testMethodCfg.TestParams.SimultWithNext; } }
#region Configuration Change Handling
public static void OnCfgChange(object sender, CfgChangeArgs args)
{
if (CfgChangeHandler == null) return;
try { CfgChangeHandler(sender, args); }
catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); }
}
public static event EventHandler<CfgChangeArgs> CfgChangeHandler;
public override void StartChangeHandler()
{
CfgChangeHandler += delegate(object sender, CfgChangeArgs args)
{
TestMethodCfg tmpCfg = args.Cfg as TestMethodCfg;
if (tmpCfg != null && tmpCfg.Name.Equals(Name))
{
if (args.Command == CfgChangeCmd.CfgChange)
{
testMethodCfg.CommTimeout = tmpCfg.CommTimeout;
testMethodCfg.DelayBetweenRetries = tmpCfg.DelayBetweenRetries;
testMethodCfg.MaxCommRetries = tmpCfg.MaxCommRetries;
testMethodCfg.IperlCheckErrorsToStop = tmpCfg.IperlCheckErrorsToStop;
testMethodCfg.UseWebService = tmpCfg.UseWebService;
testMethodCfg.BaseUrl = tmpCfg.BaseUrl;
testMethodCfg.RelativeUrl = tmpCfg.RelativeUrl;
}
}
};
}
#endregion Configuration Change Handling
readonly TestMethodCfg testMethodCfg;
public bool[] IperlCommMilestone;
IList<IOperation> sequenceConditionOps;
public TestMethod()
{
CreateMilestonesAndConditions();
}
public TestMethod(Generic.IComponentCfg cfg)
: base(cfg)
{
testMethodCfg = cfg as TestMethodCfg;
CreateMilestonesAndConditions();
}
void CreateMilestonesAndConditions()
{
IperlCommMilestone = new bool[(int)ConditionID.Count];
sequenceConditionOps = new List<IOperation>();
for (ConditionID id = ConditionID.A; id < ConditionID.Count; id++)
{
sequenceConditionOps.Add(new SequenceConditionOp(this, id));
}
}
/// IDevice interface - only Initialize() is used
public override void Initialize()
{
if (DebugLevel == DebugMode.Normal)
{
rfidDataLogger.Fatal("------------------------------------------------------------------------");
rfidDataLogger.FatalFormat("Test Bench Framework ver. {0}", Program.Version);
log.FatalFormat("{0} initialized: {1}", Name, this);
}
else
{
log.FatalFormat("{0} simulated: {1}", Name, this);
}
}
public IList<Event> Execute(Test test, int repetNr, bool isLastRepetition)
{
if (DebugLevel == DebugMode.Normal)
{
return (new GenesisCommunicationSeq()).Execute(test, repetNr, this, testMethodCfg.TestParams);
}
else
{
/// DebugLevel == DebugMode.Simulate
(new GenesisCommunicationSeq()).MakeSimulatedTrivial(test, repetNr, test.Part);
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, 1, Progress.Completed));
Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, ProcessData.BatchRslts.GetTestRslt(Common.Utils.GetTestName(test.Name, 1, 1), 0)));
return new List<Event> { Event.Done };
}
}
public int ConditionsCount { get { return (int)ConditionID.Count; } }
public string ConditionName(int i)
{
return (i >= 0 && i < (int)ConditionID.Count) ? ConditionOp(i).ToString() : string.Empty;
}
public IOperation ConditionOp(int i)
{
return (i >= 0 && i < (int)ConditionID.Count) ? sequenceConditionOps[i] : null;
}
public void StartSession()
{
/// Clear milestones
if (IperlCommMilestone != null)
{
for (int i = 0; i < IperlCommMilestone.Length; i++)
{
IperlCommMilestone[i] = false;
}
}
}
public void SaveMark(object o)
{
/// No marks
}
public void EndSession()
{
/// Nothing at the end of session
}
public bool CheckDeviceCaps(Test test, OutputPath devices, out string message)
{
// Implement the method to satisfy the ITestMethod interface.
// For now, provide a basic implementation.
message = "Device capabilities check not implemented.";
return true;
}
public override void MeterCommMilestone(int iItem, bool bValue)
{
throw new NotImplementedException();
}
public override bool IsMeterCommMilestone(int iItem)
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,96 @@
///
/// Copyright (c) 2015-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using System.IO.Ports;
using System.Xml.Serialization;
using Common;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
namespace TBF.Rig.TestMethods.GenesisFullCommunication
{
[XmlRoot("TestMethodCfg")] // Add this attribute to match the XML root
public class TestMethodCfg : ComponentCfgBase, ITestMethodCfg/*IComponentCfg*/
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TestMethodCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new TestMethodCfgCtrl(); }
//
public override IParamsProvider GetRuntimeTestParamsProvider() { return TestParams; }
public override IParamsProvider CreateTestParamsProvider() { return new GenesisCommunicationParams(true); }
public override IParamsProvider GetUITestParamsProvider(Test test)
{
return (test.Method == Name) ? base.GetUITestParamsProvider(test) : null;
}
/// Private parameterless constructor invoked by all other (public) constructors
TestMethodCfg()
{
Name = "GenesisFullCommunication";
ParentName = string.Empty;
CommTimeout = 1800; /// ms
MaxCommRetries = 4;
WaitTimeAfterFailure = 2200;
PassThroughWaitTime = 1500;
NrThreads = 2; /// 1, 2 or 4 threads
IperlCheckErrorsToStop = 10;
MciTimeoutMs = 4000; // ms, NFC interface
BaudRate = 57600; // NFC Interface
DataBits = 8; // NFC Interface
ParityBit = Parity.None; // NFC Interface
StopBits = StopBits.Two; // NFC Interface
TestParams = CreateTestParamsProvider() as GenesisCommunicationParams;
}
public TestMethodCfg(IComponentFactory factory)
: this()
{
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format("Name={0}, CommTimeout={1}, MaxRetries={2}, NrThreads={3}", Name, CommTimeout, MaxCommRetries, NrThreads);
}
public int DelayBetweenRetries { get; set; }
public int MaxCommRetries { get; set; }
public int WaitTimeAfterFailure { get; set; }
public int PassThroughWaitTime { get; set; }
public int NrThreads { get; set; }
public int CommTimeout { get; set; }
public int IperlCheckErrorsToStop { get; set; }
public int MciTimeoutMs { get; set; }
public int BaudRate { get; set; }
public int DataBits { get; set; }
public Parity ParityBit { get; set; }
public StopBits StopBits { get; set; }
public int DfltQ2c_15_rl { get; set; }
public int DfltQ2c_15_lr { get; set; }
public int DfltQ2c_20_rl { get; set; }
public int DfltQ2c_20_lr { get; set; }
public int DfltQ2c_25_63_rl { get; set; }
public int DfltQ2c_25_63_lr { get; set; }
public int DfltQ2c_25_10_rl { get; set; }
public int DfltQ2c_25_10_lr { get; set; }
public int DfltQ2c_32_rl { get; set; }
public int DfltQ2c_32_lr { get; set; }
public int DfltQ2c_40_rl { get; set; }
public int DfltQ2c_40_lr { get; set; }
public bool UseWebService { get; set; }
public string BaseUrl { get; set; }
public string RelativeUrl { get; set; }
///Remember to Ignore in XmlSerializer !!
[XmlIgnore]
public ITestParams TestParams { get; set; }
}
}
@@ -0,0 +1,299 @@
///
/// Copyright (c) 2015-2020 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using Common;
using TBF.Resources;
using TBF.Rig.Generic;
namespace TBF.Rig.TestMethods.GenesisFullCommunication
{
public partial class TestMethodCfgCtrl : Configs.ConfigCtrlUtils, IComponentCfgCtrl
{
public bool ShowMore { get { return false; } }
TestMethodCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as TestMethodCfg;
Redraw();
}
}
public TestMethodCfgCtrl()
{
InitializeComponent();
}
private void EntryFormCfgCtrl_Load(object sender, EventArgs e)
{
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
commTimeoutTextBox.Text = config.CommTimeout.ToString();
maxCommRetriesTextBox.Text = config.MaxCommRetries.ToString();
delayBetweenRetriesTextBox.Text = config.DelayBetweenRetries.ToString();
nrThreadsTextBox.Text = config.NrThreads.ToString();
iperlCheckErrorsToStopTextBox.Text = config.IperlCheckErrorsToStop.ToString();
textBox15rl.Text = config.DfltQ2c_15_rl.ToString();
textBox15lr.Text = config.DfltQ2c_15_lr.ToString();
textBox20rl.Text = config.DfltQ2c_20_rl.ToString();
textBox20lr.Text = config.DfltQ2c_20_lr.ToString();
textBox25_63rl.Text = config.DfltQ2c_25_63_rl.ToString();
textBox25_63lr.Text = config.DfltQ2c_25_63_lr.ToString();
textBox25_10rl.Text = config.DfltQ2c_25_10_rl.ToString();
textBox25_10lr.Text = config.DfltQ2c_25_10_lr.ToString();
textBox32rl.Text = config.DfltQ2c_32_rl.ToString();
textBox32lr.Text = config.DfltQ2c_32_lr.ToString();
textBox40rl.Text = config.DfltQ2c_40_rl.ToString();
textBox40lr.Text = config.DfltQ2c_40_lr.ToString();
useWebServiceCheckBox.Checked = config.UseWebService;
baseUrlTextBox.Text = config.BaseUrl;
relativeUrlTextBox.Text = config.RelativeUrl;
}
public void Unlock()
{
nameTextBox.Enabled = true;
commTimeoutTextBox.Enabled = true;
maxCommRetriesTextBox.Enabled = true;
delayBetweenRetriesTextBox.Enabled = true;
nrThreadsTextBox.Enabled = true;
iperlCheckErrorsToStopTextBox.Enabled = true;
textBox15rl.Enabled = true;
textBox15lr.Enabled = true;
textBox20rl.Enabled = true;
textBox20lr.Enabled = true;
textBox25_63rl.Enabled = true;
textBox25_63lr.Enabled = true;
textBox25_10rl.Enabled = true;
textBox25_10lr.Enabled = true;
textBox32rl.Enabled = true;
textBox32lr.Enabled = true;
textBox40rl.Enabled = true;
textBox40lr.Enabled = true;
useWebServiceCheckBox.Enabled = true;
ManageCheckGroupBox(useWebServiceCheckBox, useWebServiceGroupBox);
baseUrlTextBox.Enabled = useWebServiceCheckBox.Enabled;
relativeUrlTextBox.Enabled = useWebServiceCheckBox.Enabled;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!int.TryParse(commTimeoutTextBox.Text, out dummy) || dummy < 500 || dummy > 5000)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Comm. timeout' should be in range 500 .. 5000";
}
if (!int.TryParse(maxCommRetriesTextBox.Text, out dummy) || dummy < 1 || dummy > 10)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Max. retries' should be in range 1 .. 10";
}
if (!int.TryParse(delayBetweenRetriesTextBox.Text, out dummy) || dummy < 0 || dummy > 5000)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Comm. timeout' should be in range 0 .. 5000";
}
if (!int.TryParse(nrThreadsTextBox.Text, out dummy) || (dummy != 1 && dummy != 2 && dummy != 4))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Nr. threads' should be 1, 2 or 4";
}
if (!int.TryParse(iperlCheckErrorsToStopTextBox.Text, out dummy) || ((dummy < 1) && (dummy > 40)))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + string.Format(Strings.Invalid_0, iperlCheckErrorsToStopLabel.Text);
}
if (!int.TryParse(textBox15rl.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN15 RL should be in range -50 .. 50";
}
if (!int.TryParse(textBox15lr.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN15 LR should be in range -50 .. 50";
}
if (!int.TryParse(textBox20rl.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN20 RL should be in range -50 .. 50";
}
if (!int.TryParse(textBox20lr.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN20 LR should be in range -50 .. 50";
}
if (!int.TryParse(textBox25_63rl.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN25 Q3 6.3 RL should be in range -50 .. 50";
}
if (!int.TryParse(textBox25_63lr.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN25 Q3 6.3 LR should be in range -50 .. 50";
}
if (!int.TryParse(textBox25_10rl.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN25 Q3 10 RL should be in range -50 .. 50";
}
if (!int.TryParse(textBox25_10lr.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN25 Q3 10 LR should be in range -50 .. 50";
}
if (!int.TryParse(textBox32rl.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN32 RL should be in range -50 .. 50";
}
if (!int.TryParse(textBox32lr.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN32 LR should be in range -50 .. 50";
}
if (!int.TryParse(textBox40rl.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN40 RL should be in range -50 .. 50";
}
if (!int.TryParse(textBox40lr.Text, out dummy) || dummy < -50 || dummy > 50)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Default Q2 correction factor DN40 LR should be in range -50 .. 50";
}
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
if (config.Name != nameTextBox.Text)
{
config.Name = nameTextBox.Text;
flags |= (CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
}
var CommTimeout = config.CommTimeout;;
var MaxCommRetries = config.MaxCommRetries;
var DelayBetweenRetries = config.DelayBetweenRetries;
var NrThreads = config.NrThreads;
var IperlCheckErrorsToStop = config.IperlCheckErrorsToStop;
var DfltQ2c_15_rl = config.DfltQ2c_15_rl;
var DfltQ2c_15_lr = config.DfltQ2c_15_lr;
var DfltQ2c_20_rl = config.DfltQ2c_20_rl;
var DfltQ2c_20_lr = config.DfltQ2c_20_lr;
var DfltQ2c_25_63_rl = config.DfltQ2c_25_63_rl;
var DfltQ2c_25_63_lr = config.DfltQ2c_25_63_lr;
var DfltQ2c_25_10_rl = config.DfltQ2c_25_10_rl;
var DfltQ2c_25_10_lr = config.DfltQ2c_25_10_lr;
var DfltQ2c_32_rl = config.DfltQ2c_32_rl;
var DfltQ2c_32_lr = config.DfltQ2c_32_lr;
var DfltQ2c_40_rl = config.DfltQ2c_40_rl;
var DfltQ2c_40_lr = config.DfltQ2c_40_lr;
var UseWebService = config.UseWebService;
var BaseUrl = config.BaseUrl;
var RelativeUrl = config.RelativeUrl;
flags |= UpdateDifferent(ref CommTimeout, commTimeoutTextBox.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref MaxCommRetries, maxCommRetriesTextBox.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DelayBetweenRetries, delayBetweenRetriesTextBox.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref NrThreads, nrThreadsTextBox.Text, CfgUpdateFlags.RestartRqrd | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref IperlCheckErrorsToStop, iperlCheckErrorsToStopTextBox.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_15_rl, textBox15rl.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_15_lr, textBox15lr.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_20_rl, textBox20rl.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_20_lr, textBox20lr.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_25_63_rl, textBox25_63rl.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_25_63_lr, textBox25_63lr.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_25_10_rl, textBox25_10rl.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_25_10_lr, textBox25_10lr.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_32_rl, textBox32rl.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_32_lr, textBox32lr.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_40_rl, textBox40rl.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref DfltQ2c_40_lr, textBox40lr.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref UseWebService, useWebServiceCheckBox.Checked, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref BaseUrl, baseUrlTextBox.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
flags |= UpdateDifferent(ref RelativeUrl, relativeUrlTextBox.Text, CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.AnyChange);
config.CommTimeout = CommTimeout;
config.MaxCommRetries = MaxCommRetries;
config.DelayBetweenRetries = DelayBetweenRetries;
config.NrThreads = NrThreads;
config.IperlCheckErrorsToStop = IperlCheckErrorsToStop;
config.DfltQ2c_15_rl = DfltQ2c_15_rl;
config.DfltQ2c_15_lr = DfltQ2c_15_lr;
config.DfltQ2c_20_rl = DfltQ2c_20_rl;
config.DfltQ2c_20_lr = DfltQ2c_20_lr;
config.DfltQ2c_25_63_rl = DfltQ2c_25_63_rl;
config.DfltQ2c_25_63_lr = DfltQ2c_25_63_lr;
config.DfltQ2c_25_10_rl = DfltQ2c_25_10_rl;
config.DfltQ2c_25_10_lr = DfltQ2c_25_10_lr;
config.DfltQ2c_32_rl = DfltQ2c_32_rl;
config.DfltQ2c_32_lr = DfltQ2c_32_lr;
config.DfltQ2c_40_rl = DfltQ2c_40_rl;
config.DfltQ2c_40_lr = DfltQ2c_40_lr;
config.UseWebService = UseWebService;
config.BaseUrl = BaseUrl;
config.RelativeUrl = RelativeUrl;
if ((flags & CfgUpdateFlags.InvokeCfgChange) != 0)
{
iPerlCommunication.TestMethod.OnCfgChange(this, new CfgChangeArgs(CfgChangeCmd.CfgChange, config));
}
return flags;
}
private void ManageCheckGroupBox(CheckBox chk, GroupBox grp)
{
/// Make sure the CheckBox isn't in the GroupBox. This will only happen the first time.
if (chk.Parent == grp)
{
grp.Parent.Controls.Add(chk); /// Reparent the CheckBox so it's not in the GroupBox.
chk.Location = new System.Drawing.Point(chk.Left + grp.Left, chk.Top + grp.Top); /// Adjust the CheckBox's location.
chk.BringToFront(); /// Move the CheckBox to the top of the stacking order.
}
/// Enable or disable the GroupBox.
grp.Enabled = chk.Checked;
}
private void useWebServiceCheckBox_CheckedChanged(object sender, EventArgs e)
{
useWebServiceGroupBox.Enabled = useWebServiceCheckBox.Checked;
}
}
}
@@ -0,0 +1,520 @@
///
/// Copyright (c) 2015 Sensus Metering Systems
/// Author: Milan Hanajík
///
namespace TBF.Rig.TestMethods.GenesisFullCommunication
{
partial class TestMethodCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.commTimeoutTextBox = new System.Windows.Forms.TextBox();
this.commTimeoutLabel = new System.Windows.Forms.Label();
this.maxCommRetriesTextBox = new System.Windows.Forms.TextBox();
this.maxNrRetriesLabel = new System.Windows.Forms.Label();
this.nrThreadsTextBox = new System.Windows.Forms.TextBox();
this.nrThreadsLabel = new System.Windows.Forms.Label();
this.iperlCheckErrorsToStopTextBox = new System.Windows.Forms.TextBox();
this.iperlCheckErrorsToStopLabel = new System.Windows.Forms.Label();
this.delayBetweenRetriesTextBox = new System.Windows.Forms.TextBox();
this.delayBetweenRetriesLabel = new System.Windows.Forms.Label();
this.relativeUrlTextBox = new System.Windows.Forms.TextBox();
this.relativeUrlLabel = new System.Windows.Forms.Label();
this.baseUrlTextBox = new System.Windows.Forms.TextBox();
this.baseUrlLabel = new System.Windows.Forms.Label();
this.useWebServiceCheckBox = new System.Windows.Forms.CheckBox();
this.useWebServiceGroupBox = new System.Windows.Forms.GroupBox();
this.dfltQ2corrFactorsGroupBox = new System.Windows.Forms.GroupBox();
this.label8 = new System.Windows.Forms.Label();
this.label7 = new System.Windows.Forms.Label();
this.label6 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.textBox40lr = new System.Windows.Forms.TextBox();
this.textBox32lr = new System.Windows.Forms.TextBox();
this.textBox25_10lr = new System.Windows.Forms.TextBox();
this.textBox25_63lr = new System.Windows.Forms.TextBox();
this.textBox20lr = new System.Windows.Forms.TextBox();
this.textBox15lr = new System.Windows.Forms.TextBox();
this.textBox40rl = new System.Windows.Forms.TextBox();
this.textBox32rl = new System.Windows.Forms.TextBox();
this.textBox25_10rl = new System.Windows.Forms.TextBox();
this.textBox25_63rl = new System.Windows.Forms.TextBox();
this.textBox20rl = new System.Windows.Forms.TextBox();
this.textBox15rl = new System.Windows.Forms.TextBox();
this.useWebServiceGroupBox.SuspendLayout();
this.dfltQ2corrFactorsGroupBox.SuspendLayout();
this.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(237, 31);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(23, 34);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(234, 11);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// commTimeoutTextBox
//
this.commTimeoutTextBox.Enabled = false;
this.commTimeoutTextBox.Location = new System.Drawing.Point(237, 53);
this.commTimeoutTextBox.Name = "commTimeoutTextBox";
this.commTimeoutTextBox.Size = new System.Drawing.Size(45, 20);
this.commTimeoutTextBox.TabIndex = 4;
//
// commTimeoutLabel
//
this.commTimeoutLabel.AutoSize = true;
this.commTimeoutLabel.Location = new System.Drawing.Point(23, 56);
this.commTimeoutLabel.Name = "commTimeoutLabel";
this.commTimeoutLabel.Size = new System.Drawing.Size(98, 13);
this.commTimeoutLabel.TabIndex = 3;
this.commTimeoutLabel.Text = "Comm. timeout [ms]";
//
// maxCommRetriesTextBox
//
this.maxCommRetriesTextBox.Enabled = false;
this.maxCommRetriesTextBox.Location = new System.Drawing.Point(237, 75);
this.maxCommRetriesTextBox.Name = "maxCommRetriesTextBox";
this.maxCommRetriesTextBox.Size = new System.Drawing.Size(45, 20);
this.maxCommRetriesTextBox.TabIndex = 6;
//
// maxNrRetriesLabel
//
this.maxNrRetriesLabel.AutoSize = true;
this.maxNrRetriesLabel.Location = new System.Drawing.Point(23, 78);
this.maxNrRetriesLabel.Name = "maxNrRetriesLabel";
this.maxNrRetriesLabel.Size = new System.Drawing.Size(61, 13);
this.maxNrRetriesLabel.TabIndex = 5;
this.maxNrRetriesLabel.Text = "Max. retries";
//
// nrThreadsTextBox
//
this.nrThreadsTextBox.Enabled = false;
this.nrThreadsTextBox.Location = new System.Drawing.Point(237, 119);
this.nrThreadsTextBox.Name = "nrThreadsTextBox";
this.nrThreadsTextBox.Size = new System.Drawing.Size(45, 20);
this.nrThreadsTextBox.TabIndex = 10;
//
// nrThreadsLabel
//
this.nrThreadsLabel.AutoSize = true;
this.nrThreadsLabel.Location = new System.Drawing.Point(23, 122);
this.nrThreadsLabel.Name = "nrThreadsLabel";
this.nrThreadsLabel.Size = new System.Drawing.Size(59, 13);
this.nrThreadsLabel.TabIndex = 9;
this.nrThreadsLabel.Text = "Nr. threads";
//
// iperlCheckErrorsToStopTextBox
//
this.iperlCheckErrorsToStopTextBox.Enabled = false;
this.iperlCheckErrorsToStopTextBox.Location = new System.Drawing.Point(237, 141);
this.iperlCheckErrorsToStopTextBox.Name = "iperlCheckErrorsToStopTextBox";
this.iperlCheckErrorsToStopTextBox.Size = new System.Drawing.Size(45, 20);
this.iperlCheckErrorsToStopTextBox.TabIndex = 13;
//
// iperlCheckErrorsToStopLabel
//
this.iperlCheckErrorsToStopLabel.AutoSize = true;
this.iperlCheckErrorsToStopLabel.Location = new System.Drawing.Point(23, 144);
this.iperlCheckErrorsToStopLabel.Name = "iperlCheckErrorsToStopLabel";
this.iperlCheckErrorsToStopLabel.Size = new System.Drawing.Size(202, 13);
this.iperlCheckErrorsToStopLabel.TabIndex = 12;
this.iperlCheckErrorsToStopLabel.Text = "iperl_check errors count to stop the cycle";
//
// delayBetweenRetriesTextBox
//
this.delayBetweenRetriesTextBox.Enabled = false;
this.delayBetweenRetriesTextBox.Location = new System.Drawing.Point(237, 97);
this.delayBetweenRetriesTextBox.Name = "delayBetweenRetriesTextBox";
this.delayBetweenRetriesTextBox.Size = new System.Drawing.Size(45, 20);
this.delayBetweenRetriesTextBox.TabIndex = 8;
//
// delayBetweenRetriesLabel
//
this.delayBetweenRetriesLabel.AutoSize = true;
this.delayBetweenRetriesLabel.Location = new System.Drawing.Point(23, 100);
this.delayBetweenRetriesLabel.Name = "delayBetweenRetriesLabel";
this.delayBetweenRetriesLabel.Size = new System.Drawing.Size(131, 13);
this.delayBetweenRetriesLabel.TabIndex = 7;
this.delayBetweenRetriesLabel.Text = "Delay between retries [ms]";
//
// relativeUrlTextBox
//
this.relativeUrlTextBox.Enabled = false;
this.relativeUrlTextBox.Location = new System.Drawing.Point(89, 50);
this.relativeUrlTextBox.Name = "relativeUrlTextBox";
this.relativeUrlTextBox.Size = new System.Drawing.Size(298, 20);
this.relativeUrlTextBox.TabIndex = 18;
//
// relativeUrlLabel
//
this.relativeUrlLabel.AutoSize = true;
this.relativeUrlLabel.Location = new System.Drawing.Point(13, 53);
this.relativeUrlLabel.Name = "relativeUrlLabel";
this.relativeUrlLabel.Size = new System.Drawing.Size(71, 13);
this.relativeUrlLabel.TabIndex = 17;
this.relativeUrlLabel.Text = "Relative URL";
//
// baseUrlTextBox
//
this.baseUrlTextBox.Enabled = false;
this.baseUrlTextBox.Location = new System.Drawing.Point(89, 24);
this.baseUrlTextBox.Name = "baseUrlTextBox";
this.baseUrlTextBox.Size = new System.Drawing.Size(298, 20);
this.baseUrlTextBox.TabIndex = 16;
//
// baseUrlLabel
//
this.baseUrlLabel.AutoSize = true;
this.baseUrlLabel.Location = new System.Drawing.Point(13, 27);
this.baseUrlLabel.Name = "baseUrlLabel";
this.baseUrlLabel.Size = new System.Drawing.Size(56, 13);
this.baseUrlLabel.TabIndex = 15;
this.baseUrlLabel.Text = "Base URL";
//
// useWebServiceCheckBox
//
this.useWebServiceCheckBox.AutoSize = true;
this.useWebServiceCheckBox.Enabled = false;
this.useWebServiceCheckBox.Location = new System.Drawing.Point(15, 0);
this.useWebServiceCheckBox.Name = "useWebServiceCheckBox";
this.useWebServiceCheckBox.Size = new System.Drawing.Size(189, 17);
this.useWebServiceCheckBox.TabIndex = 14;
this.useWebServiceCheckBox.Text = "Use web service for default values";
this.useWebServiceCheckBox.UseVisualStyleBackColor = true;
this.useWebServiceCheckBox.CheckedChanged += new System.EventHandler(this.useWebServiceCheckBox_CheckedChanged);
//
// useWebServiceGroupBox
//
this.useWebServiceGroupBox.Controls.Add(this.baseUrlTextBox);
this.useWebServiceGroupBox.Controls.Add(this.useWebServiceCheckBox);
this.useWebServiceGroupBox.Controls.Add(this.relativeUrlTextBox);
this.useWebServiceGroupBox.Controls.Add(this.relativeUrlLabel);
this.useWebServiceGroupBox.Controls.Add(this.baseUrlLabel);
this.useWebServiceGroupBox.Location = new System.Drawing.Point(11, 266);
this.useWebServiceGroupBox.Name = "useWebServiceGroupBox";
this.useWebServiceGroupBox.Size = new System.Drawing.Size(404, 83);
this.useWebServiceGroupBox.TabIndex = 0;
this.useWebServiceGroupBox.TabStop = false;
//
// dfltQ2corrFactorsGroupBox
//
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.label8);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.label7);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.label6);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.label5);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.label4);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.label3);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.label2);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.label1);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox40lr);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox32lr);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox25_10lr);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox25_63lr);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox20lr);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox15lr);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox40rl);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox32rl);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox25_10rl);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox25_63rl);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox20rl);
this.dfltQ2corrFactorsGroupBox.Controls.Add(this.textBox15rl);
this.dfltQ2corrFactorsGroupBox.Location = new System.Drawing.Point(11, 175);
this.dfltQ2corrFactorsGroupBox.Name = "dfltQ2corrFactorsGroupBox";
this.dfltQ2corrFactorsGroupBox.Size = new System.Drawing.Size(404, 85);
this.dfltQ2corrFactorsGroupBox.TabIndex = 14;
this.dfltQ2corrFactorsGroupBox.TabStop = false;
this.dfltQ2corrFactorsGroupBox.Text = "Default Q2 correction factors";
//
// label8
//
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(344, 17);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(35, 13);
this.label8.TabIndex = 19;
this.label8.Text = "DN40";
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(289, 17);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(35, 13);
this.label7.TabIndex = 18;
this.label7.Text = "DN32";
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(233, 17);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(45, 13);
this.label6.TabIndex = 17;
this.label6.Text = "...Q3 10";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(163, 17);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(70, 13);
this.label5.TabIndex = 16;
this.label5.Text = "DN25 Q3 6.3";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(121, 17);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(35, 13);
this.label4.TabIndex = 15;
this.label4.Text = "DN20";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(65, 17);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(35, 13);
this.label3.TabIndex = 14;
this.label3.Text = "DN15";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(22, 57);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(24, 13);
this.label2.TabIndex = 13;
this.label2.Text = "L-R";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(22, 34);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(24, 13);
this.label1.TabIndex = 12;
this.label1.Text = "R-L";
//
// textBox40lr
//
this.textBox40lr.Enabled = false;
this.textBox40lr.Location = new System.Drawing.Point(337, 54);
this.textBox40lr.Name = "textBox40lr";
this.textBox40lr.Size = new System.Drawing.Size(50, 20);
this.textBox40lr.TabIndex = 11;
//
// textBox32lr
//
this.textBox32lr.Enabled = false;
this.textBox32lr.Location = new System.Drawing.Point(281, 54);
this.textBox32lr.Name = "textBox32lr";
this.textBox32lr.Size = new System.Drawing.Size(50, 20);
this.textBox32lr.TabIndex = 10;
//
// textBox25_10lr
//
this.textBox25_10lr.Enabled = false;
this.textBox25_10lr.Location = new System.Drawing.Point(225, 54);
this.textBox25_10lr.Name = "textBox25_10lr";
this.textBox25_10lr.Size = new System.Drawing.Size(50, 20);
this.textBox25_10lr.TabIndex = 9;
//
// textBox25_63lr
//
this.textBox25_63lr.Enabled = false;
this.textBox25_63lr.Location = new System.Drawing.Point(169, 54);
this.textBox25_63lr.Name = "textBox25_63lr";
this.textBox25_63lr.Size = new System.Drawing.Size(50, 20);
this.textBox25_63lr.TabIndex = 8;
//
// textBox20lr
//
this.textBox20lr.Enabled = false;
this.textBox20lr.Location = new System.Drawing.Point(113, 54);
this.textBox20lr.Name = "textBox20lr";
this.textBox20lr.Size = new System.Drawing.Size(50, 20);
this.textBox20lr.TabIndex = 7;
//
// textBox15lr
//
this.textBox15lr.Enabled = false;
this.textBox15lr.Location = new System.Drawing.Point(57, 54);
this.textBox15lr.Name = "textBox15lr";
this.textBox15lr.Size = new System.Drawing.Size(50, 20);
this.textBox15lr.TabIndex = 6;
//
// textBox40rl
//
this.textBox40rl.Enabled = false;
this.textBox40rl.Location = new System.Drawing.Point(337, 31);
this.textBox40rl.Name = "textBox40rl";
this.textBox40rl.Size = new System.Drawing.Size(50, 20);
this.textBox40rl.TabIndex = 5;
//
// textBox32rl
//
this.textBox32rl.Enabled = false;
this.textBox32rl.Location = new System.Drawing.Point(281, 31);
this.textBox32rl.Name = "textBox32rl";
this.textBox32rl.Size = new System.Drawing.Size(50, 20);
this.textBox32rl.TabIndex = 4;
//
// textBox25_10rl
//
this.textBox25_10rl.Enabled = false;
this.textBox25_10rl.Location = new System.Drawing.Point(225, 31);
this.textBox25_10rl.Name = "textBox25_10rl";
this.textBox25_10rl.Size = new System.Drawing.Size(50, 20);
this.textBox25_10rl.TabIndex = 3;
//
// textBox25_63rl
//
this.textBox25_63rl.Enabled = false;
this.textBox25_63rl.Location = new System.Drawing.Point(169, 31);
this.textBox25_63rl.Name = "textBox25_63rl";
this.textBox25_63rl.Size = new System.Drawing.Size(50, 20);
this.textBox25_63rl.TabIndex = 2;
//
// textBox20rl
//
this.textBox20rl.Enabled = false;
this.textBox20rl.Location = new System.Drawing.Point(113, 31);
this.textBox20rl.Name = "textBox20rl";
this.textBox20rl.Size = new System.Drawing.Size(50, 20);
this.textBox20rl.TabIndex = 1;
//
// textBox15rl
//
this.textBox15rl.Enabled = false;
this.textBox15rl.Location = new System.Drawing.Point(57, 31);
this.textBox15rl.Name = "textBox15rl";
this.textBox15rl.Size = new System.Drawing.Size(50, 20);
this.textBox15rl.TabIndex = 0;
//
// TestMethodCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.dfltQ2corrFactorsGroupBox);
this.Controls.Add(this.useWebServiceGroupBox);
this.Controls.Add(this.delayBetweenRetriesTextBox);
this.Controls.Add(this.delayBetweenRetriesLabel);
this.Controls.Add(this.iperlCheckErrorsToStopTextBox);
this.Controls.Add(this.iperlCheckErrorsToStopLabel);
this.Controls.Add(this.nrThreadsTextBox);
this.Controls.Add(this.nrThreadsLabel);
this.Controls.Add(this.maxCommRetriesTextBox);
this.Controls.Add(this.maxNrRetriesLabel);
this.Controls.Add(this.commTimeoutTextBox);
this.Controls.Add(this.commTimeoutLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "TestMethodCfgCtrl";
this.Size = new System.Drawing.Size(427, 363);
this.Load += new System.EventHandler(this.EntryFormCfgCtrl_Load);
this.useWebServiceGroupBox.ResumeLayout(false);
this.useWebServiceGroupBox.PerformLayout();
this.dfltQ2corrFactorsGroupBox.ResumeLayout(false);
this.dfltQ2corrFactorsGroupBox.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.TextBox commTimeoutTextBox;
private System.Windows.Forms.Label commTimeoutLabel;
private System.Windows.Forms.TextBox maxCommRetriesTextBox;
private System.Windows.Forms.Label maxNrRetriesLabel;
private System.Windows.Forms.TextBox nrThreadsTextBox;
private System.Windows.Forms.Label nrThreadsLabel;
private System.Windows.Forms.TextBox iperlCheckErrorsToStopTextBox;
private System.Windows.Forms.Label iperlCheckErrorsToStopLabel;
private System.Windows.Forms.TextBox delayBetweenRetriesTextBox;
private System.Windows.Forms.Label delayBetweenRetriesLabel;
private System.Windows.Forms.TextBox relativeUrlTextBox;
private System.Windows.Forms.Label relativeUrlLabel;
private System.Windows.Forms.TextBox baseUrlTextBox;
private System.Windows.Forms.Label baseUrlLabel;
private System.Windows.Forms.CheckBox useWebServiceCheckBox;
private System.Windows.Forms.GroupBox useWebServiceGroupBox;
private System.Windows.Forms.GroupBox dfltQ2corrFactorsGroupBox;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox40lr;
private System.Windows.Forms.TextBox textBox32lr;
private System.Windows.Forms.TextBox textBox25_10lr;
private System.Windows.Forms.TextBox textBox25_63lr;
private System.Windows.Forms.TextBox textBox20lr;
private System.Windows.Forms.TextBox textBox15lr;
private System.Windows.Forms.TextBox textBox40rl;
private System.Windows.Forms.TextBox textBox32rl;
private System.Windows.Forms.TextBox textBox25_10rl;
private System.Windows.Forms.TextBox textBox25_63rl;
private System.Windows.Forms.TextBox textBox20rl;
private System.Windows.Forms.TextBox textBox15rl;
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+11 -10
View File
@@ -6,20 +6,21 @@ using TBF.Rig.Generic;
namespace TBF.Rig.Uni.FlowMetersInParallel
{
public class Factory : IComponentFactory
{
public class Factory : IComponentFactory
{
public string ClassName { get { return GetType().Namespace.Substring(12); } }
public override string ToString() { return ClassName; }
public IComponent DummyComponent() { return new FlowMeter(); }
public IComponent DummyComponent() { return new FlowMeter(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new FlowMeter(cfg, components); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new FlowMeter(cfg, components); }
public IComponentCfg DefaultConfig() { return new FlowMeterCfg(this, "I11+I12"); }
public IComponentCfg DefaultConfig() { return new FlowMeterCfg(this, "I11+I12"); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(FlowMeterCfg.Serializer, component, this);
}
}
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(FlowMeterCfg.Serializer, component, this);
}
}
}
+62 -51
View File
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using log4net;
using SchematicDrawing;
using SharedComponents;
using TBF.Boxes;
using TBF.Rig.ControlBoard.Uni;
using TBF.Rig.GenericDevices;
@@ -12,17 +13,16 @@ using TBF.Rig.GenericDevices;
namespace TBF.Rig.Uni.FlowMetersInParallel
{
public class FlowMeter : ComponentBase, IFlowMeter, IDrawingItCmpntWithMeasuredVal
{
private static readonly ILog log = LogManager.GetLogger(typeof(FlowMeter));
{
private static readonly ILog log = LogManager.GetLogger(typeof(FlowMeter));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
readonly FlowMeterCfg myCfg;
readonly FlowMeterCfg flowMeterCfg;
UniCB uniCB;
IFlowMeterSingle flowMtr1;
IFlowMeterSingle flowMtr2;
IFlowMeterSingle flowMtr3;
IFlowMeterSingle inactiveFlowMtr;
double nominalFlow;
double nominalFreq;
double ltrPerPulse;
@@ -34,22 +34,20 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
public double NominalFreq { get { return nominalFreq; } }
public double LtrPerPulse { get { return ltrPerPulse; } }
public SchematicDrawing.IDrawingItem DrawingItem { get { return myCfg as SchematicDrawing.IDrawingItem; } }
public string MsrdFormat { get { return myCfg.MsrdFormat; } }
public Common.Unit MsrdUnit { get { return myCfg.MsrdUnit; } }
public double MsrdValLimLo { get { return myCfg.MsrdValLimLo; } set { myCfg.MsrdValLimLo = value; } }
public double MsrdValLimHi { get { return myCfg.MsrdValLimHi; } set { myCfg.MsrdValLimHi = value; } }
public SchematicDrawing.IDrawingItem DrawingItem { get { return flowMeterCfg as SchematicDrawing.IDrawingItem; } }
public string MsrdFormat { get { return flowMeterCfg.MsrdFormat; } }
public Common.Unit MsrdUnit { get { return flowMeterCfg.MsrdUnit; } }
public double MsrdValLimLo { get { return flowMeterCfg.MsrdValLimLo; } set { flowMeterCfg.MsrdValLimLo = value; } }
public double MsrdValLimHi { get { return flowMeterCfg.MsrdValLimHi; } set { flowMeterCfg.MsrdValLimHi = value; } }
public bool MsrmntAvailable
{
get
{
bool result = true;
if (flowMtr1 != null) result = (result && flowMtr1.MsrmntAvailable);
if (flowMtr2 != null) result = (result && flowMtr2.MsrmntAvailable);
if (flowMtr3 != null) result = (result && flowMtr3.MsrmntAvailable);
if (inactiveFlowMtr != null) result = (result && !inactiveFlowMtr.MsrmntAvailable);
if (flowMtr1 != null) result = result && flowMtr1.MsrmntAvailable;
if (flowMtr2 != null) result = result && flowMtr2.MsrmntAvailable;
if (flowMtr3 != null) result = result && flowMtr3.MsrmntAvailable;
return result;
}
}
@@ -61,24 +59,22 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
public string AltString { get { return "Invalid format"; } }
public FlowMeter() { }
public FlowMeter() { }
public FlowMeter(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
myCfg = cfg as FlowMeterCfg;
}
public FlowMeter(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
flowMeterCfg = cfg as FlowMeterCfg;
}
public override void Initialize()
{
uniCB = TbfComponents.FindComponent(myCfg.ParentName) as UniCB;
uniCB = TbfComponents.FindComponent(flowMeterCfg.ParentName) as UniCB;
if (uniCB == null) throw new Exception("Cannot find " + Name + " parent");
if (!string.IsNullOrEmpty(myCfg.Flowmeter1)) flowMtr1 = TbfComponents.FindComponent(myCfg.Flowmeter1) as IFlowMeterSingle;
if (!string.IsNullOrEmpty(myCfg.Flowmeter2)) flowMtr2 = TbfComponents.FindComponent(myCfg.Flowmeter2) as IFlowMeterSingle;
if (!string.IsNullOrEmpty(myCfg.Flowmeter3)) flowMtr3 = TbfComponents.FindComponent(myCfg.Flowmeter3) as IFlowMeterSingle;
if (!string.IsNullOrEmpty(myCfg.InactiveFlowmtr)) inactiveFlowMtr = TbfComponents.FindComponent(myCfg.InactiveFlowmtr) as IFlowMeterSingle;
if (!string.IsNullOrEmpty(flowMeterCfg.Flowmeter1)) flowMtr1 = TbfComponents.FindComponent(flowMeterCfg.Flowmeter1) as IFlowMeterSingle;
if (!string.IsNullOrEmpty(flowMeterCfg.Flowmeter2)) flowMtr2 = TbfComponents.FindComponent(flowMeterCfg.Flowmeter2) as IFlowMeterSingle;
if (!string.IsNullOrEmpty(flowMeterCfg.Flowmeter3)) flowMtr3 = TbfComponents.FindComponent(flowMeterCfg.Flowmeter3) as IFlowMeterSingle;
nominalFlow = 0;
flowMetersCount = 0;
@@ -91,8 +87,8 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
flowMetersBitfield |= (4 << flowMtr1.Idx1);
flowMetersCount++;
}
if (flowMtr2 != null)
{
if (flowMtr2 != null)
{
nominalFlow += flowMtr2.NominalFlow;
nominalFreq += flowMtr2.NominalFreq;
flowMetersBitfield |= (4 << flowMtr2.Idx1);
@@ -109,15 +105,31 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
MsrdValLimHi = nominalFlow;
nominalFreq = nominalFreq / flowMetersCount;
ltrPerPulse = nominalFlow / (3.6 * nominalFreq); /// Nominal freq. is sum of particular nominal frquencies
log.FatalFormat("{0} initialized: {1} nom.flow={2} m3/h nom.freq={3} Hz bitfield=0x{4:X2}",
Name, this, nominalFlow, nominalFreq, flowMetersBitfield);
Name, true, nominalFlow, nominalFreq, flowMetersBitfield);
}
public double ReadFlow()
{
return ReadFrequency() * nominalFlow / nominalFreq;
double flowByNewFormulaSum = 0;
if (flowMtr1 != null)
{
flowByNewFormulaSum += flowMtr1.NominalFlow * uniCB.Data.ReferenceFreq[1] / flowMtr1.NominalFreq;
}
if (flowMtr2 != null)
{
flowByNewFormulaSum += flowMtr2.NominalFlow * uniCB.Data.ReferenceFreq[2] / flowMtr2.NominalFreq;
}
if (flowMtr3 != null)
{
flowByNewFormulaSum += flowMtr3.NominalFlow * uniCB.Data.ReferenceFreq[3] / flowMtr3.NominalFreq;
}
return flowByNewFormulaSum/*ReadFrequency() * nominalFlow / nominalFreq*/;
}
public double ReadFrequency()
@@ -125,27 +137,26 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
return uniCB.RefFrequency;
}
/// <summary>
/// Events: FlowDone, Error
/// </summary>
/// <param name="flow">Reference to a variable for the flow in Bar</param>
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
public IOperation ReadFlowOp(ref DoubleBox flow)
{
return new ReadFlowOp(this, ref flow);
}
/// <summary>
/// Events: flowDone, Error
/// </summary>
/// <param name="flow">Reference to a variable for the flow in Bar</param>
/// <param name="flowDone">Event returned when measurement done</param>
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
public IOperation ReadFlowOp(ref DoubleBox flow, Event flowDone)
{
return new ReadFlowOp(this, ref flow, flowDone);
}
/// <summary>
/// Events: FlowDone, Error
/// </summary>
/// <param name="flow">Reference to a variable for the flow in Bar</param>
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
public IOperation ReadFlowOp(ref DoubleBox flow)
{
return new ReadFlowOp(this, ref flow);
}
/// <summary>
/// Events: flowDone, Error
/// </summary>
/// <param name="flow">Reference to a variable for the flow in Bar</param>
/// <param name="flowDone">Event returned when measurement done</param>
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
public IOperation ReadFlowOp(ref DoubleBox flow, Event flowDone)
{
return new ReadFlowOp(this, ref flow, flowDone);
}
double flowRawSum;
double flowSum;
@@ -197,7 +208,7 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
public double LtrPerPulseCorrected(double flow, float temperature)
{
double ltrPerPulseCorrected = (flowRawSum == 0) ? LtrPerPulse : LtrPerPulse * flowSum / flowRawSum;
log.WarnFormat("LtrPerPulseCorrected() flow = {0:F3} m3/h flowRawSum = {1:F3} m3/h flowSum = {2:F3} m3/h temperature = {3:F1} C ltrPerPulseCorrected = {4}", flow, flowRawSum, flowSum, temperature, ltrPerPulseCorrected);
log.WarnFormat("LtrPerPulseCorrected() flow = {0} m3/h flowRawSum = {1} m3/h flowSum = {2} m3/h temperature = {3} C ltrPerPulseCorrected = {4}", flow, flowRawSum, flowSum, temperature, ltrPerPulseCorrected);
return ltrPerPulseCorrected;
}
}
@@ -13,9 +13,9 @@ using TBF.Rig.Generic;
namespace TBF.Rig.Uni.FlowMetersInParallel
{
public class FlowMeterCfg : ComponentCfgBase, IChildComponentCfg, IParamsProvider, IDrawingItemWithMeasuredVal
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(FlowMeterCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(FlowMeterCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities)
{
@@ -24,15 +24,14 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
return new Configs.ParamsProvider.ComponentCfgCtrl(this, parents);
}
///
/// Serialized parameters
///
///
/// Serialized parameters
///
public string Flowmeter1; /// 0 Flowmeter component name or string.Empty
public string Flowmeter2; /// 1 - ' ' -
public string Flowmeter3; /// 2 - ' ' -
public string InactiveFlowmtr; /// 3 Inactive flowmeter component name or string.Empty
public string MsrdFormat { get; set; } /// 4
public Unit MsrdUnit { get; set; } /// 5
public string MsrdFormat { get; set; } /// 3
public Unit MsrdUnit { get; set; } /// 4
/// Schematic drawing info
public Shape Shape { get; set; }
@@ -58,9 +57,6 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
private IEnumerable<Config.Entities.Component> flowMeters;
[XmlIgnore]
public bool IsOffline { get; set; }
/// Private parameterless constructor invoked by all other (public) constructors
FlowMeterCfg()
{
@@ -82,12 +78,13 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
public string ComponentName { get { return Name; } }
public bool IsOffline { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public void InitializeAll()
{
Flowmeter1 = "I11";
Flowmeter2 = "I12";
Flowmeter3 = string.Empty;
InactiveFlowmtr = "I13";
MsrdFormat = "{0:F3} m3/h";
MsrdUnit = Unit.m3ph;
}
@@ -97,9 +94,8 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
"Flow meter 1", /// 0
"Flow meter 2", /// 1
"Flow meter 3", /// 2
"Inactive flow meter", /// 3
"Display format", /// 4
"Unit of flow on a display", /// 5
"Display format", /// 3
"Unit of flow on a display", /// 4
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
@@ -111,48 +107,44 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
case 0:
case 1:
case 2:
case 3:
if (flowMeters == null) return null;
var fmtrs = new List<string>();
foreach (var fmtr in flowMeters) fmtrs.Add(fmtr.Name);
fmtrs.Add("---");
return fmtrs;
case 5:
return new string[] { "m3/h", "l/h", "gal/m" };
case 4:
return new string[] { "m3/h", "l/h" };
default:
return null;
}
}
public string ToString(int i)
{
public string ToString(int i)
{
switch (i)
{
case 0: return string.IsNullOrEmpty(Flowmeter1) ? "---" : Flowmeter1;
case 1: return string.IsNullOrEmpty(Flowmeter2) ? "---" : Flowmeter2;
case 2: return string.IsNullOrEmpty(Flowmeter3) ? "---" : Flowmeter3;
case 3: return string.IsNullOrEmpty(InactiveFlowmtr) ? "---" : InactiveFlowmtr;
case 4: return MsrdFormat;
case 5: return MsrdUnit.ToDescription();
case 3: return MsrdFormat;
case 4: return MsrdUnit.ToDescription();
default:
return string.Format("Name={0} {1} {2} {3} ~{4} fmt={5} unit={6} Lo={7} Hi={8}",
Name, Flowmeter1, Flowmeter2, Flowmeter3, InactiveFlowmtr,
return string.Format("Name={0} {1} {2} {3} fmt={4} unit={5} Lo={6} Hi={7}",
Name, Flowmeter1, Flowmeter2, Flowmeter3,
MsrdFormat, MsrdUnit.ToDescription(), MsrdValLimLo, MsrdValLimHi);
}
}
}
public CfgUpdateFlags UpdateParam(int i, string str)
{
switch (i)
{
case 0: Flowmeter1 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 1: Flowmeter2 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 2: Flowmeter3 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 3: InactiveFlowmtr = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 4: MsrdFormat = str; return CfgUpdateFlags.RestartRqrd;
//case 5: MsrdUnit = (str == "l/h") ? Unit.lph : Unit.m3ph; return CfgUpdateFlags.RestartRqrd;
case 5: MsrdUnit = ParseFlowUnit(str); return CfgUpdateFlags.RestartRqrd;
case 0: Flowmeter1 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 1: Flowmeter2 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 2: Flowmeter3 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 3: MsrdFormat = str; return CfgUpdateFlags.RestartRqrd;
case 4: MsrdUnit = (str == "l/h") ? Unit.lph : Unit.m3ph; return CfgUpdateFlags.RestartRqrd;
default:
return CfgUpdateFlags.None;
}
@@ -167,11 +159,10 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
case 0:
case 1:
case 2:
case 3:
case 5:
case 4:
if (ParamValues(i).Contains(str)) return true;
break;
case 4:
case 3:
return true;
default:
message = "Invalid index";
@@ -187,7 +178,6 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
prms.Flowmeter1 = this.Flowmeter1;
prms.Flowmeter2 = this.Flowmeter2;
prms.Flowmeter3 = this.Flowmeter3;
prms.InactiveFlowmtr = this.InactiveFlowmtr;
prms.MsrdFormat = this.MsrdFormat;
prms.MsrdUnit = this.MsrdUnit;
}
@@ -203,19 +193,5 @@ namespace TBF.Rig.Uni.FlowMetersInParallel
{
return true; /// =OK, do nothing
}
public static Unit ParseFlowUnit(string str)
{
//Check if the string is a valid unit description
Unit fromDescription = Units.FromDescription(str);
if (fromDescription != Unit.None) return fromDescription;
//check if the string is a valid unit name
switch (str)
{
case "l/h": return Unit.lph;
case "gal/m": return Unit.USgalpm;
case "m3/h":
default: return Unit.m3ph;
}
}
}
}
+33 -33
View File
@@ -8,57 +8,57 @@ using TBF.Rig.GenericDevices;
namespace TBF.Rig.Uni.FlowMetersInParallel
{
public class ReadFlowOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadFlowOp));
public class ReadFlowOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadFlowOp));
public override string ToString() { return string.Format("ReadFlowOp({0},.,.,{1})", flowMeter.Idx1, eventDone); }
/// Set by the constructor
/// Set by the constructor
readonly IFlowMeter flowMeter;
readonly DoubleBox flowBox;
readonly Event eventDone;
readonly DoubleBox flowBox;
readonly Event eventDone;
/// <summary>
/// Events: FlowInDone, FlowOutDone or Error
/// </summary>
/// <param name="flowMeter">Flow meter reference</param>
/// <param name="flowBox">Reference to the measured flow variable, value is in bar</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
/// <summary>
/// Events: FlowInDone, FlowOutDone or Error
/// </summary>
/// <param name="flowMeter">Flow meter reference</param>
/// <param name="flowBox">Reference to the measured flow variable, value is in bar</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox, Event eventDone)
{
if (flowMeter == null) throw new ArgumentNullException();
this.flowMeter = flowMeter;
this.eventDone = eventDone;
this.flowBox = flowBox;
this.eventDone = eventDone;
this.flowBox = flowBox;
log.Debug(this.ToString());
log.Debug(this.ToString());
}
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox)
: this(flowMeter, ref flowBox, Event.FlowMeasurementDone)
{
}
: this(flowMeter, ref flowBox, Event.FlowMeasurementDone)
{
}
/// <summary>Start this operation</summary>
public void Start() { }
/// <summary>Start this operation</summary>
public void Start() { }
/// <summary>Run this operation</summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
/// <summary>Run this operation</summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
if (flowMeter.MsrmntAvailable)
{
{
if (flowBox != null) flowBox.Val = flowMeter.ReadFlow();
return eventDone;
}
return eventDone;
}
return Event.Error;
}
}
/// <summary>Stop this operation</summary>
public void Stop() { }
}
/// <summary>Stop this operation</summary>
public void Stop() { }
}
}
@@ -1,10 +1,9 @@
///
/// Copyright (c) 2021-2023 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.Rig.ControlBoard.Uni;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.Uni.RegValve
@@ -14,12 +13,12 @@ namespace TBF.Rig.Uni.RegValve
private static readonly ILog log = LogManager.GetLogger(typeof(ChangeRegValvePositionOp));
public override string ToString()
{
return string.Format("ChangeRegValvePositionOp({0},{1}s)", regV.Name, timePulseSec.ToString("F2"));
return string.Format("ChangeRegValvePositionOp({0},{1}s)", regulValve.Name, timePulseSec.ToString("F2"));
}
/// Set by the constructor
readonly UniCB uniCB;
readonly RegValve regV;
readonly TBF.Rig.ControlBoard.Uni.UniCB controlBoard;
readonly RegValve regulValve;
readonly int regulValveNr;
readonly double timePulseSec;
@@ -33,14 +32,14 @@ namespace TBF.Rig.Uni.RegValve
/// <param name="posHiPct">Upper limit of the position to be achieved</param>
/// <param name="timeout">Timeout in sec. for setting the flow</param>
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
public ChangeRegValvePositionOp(UniCB uniCB, RegValve regV, double timePulseSec)
public ChangeRegValvePositionOp(TBF.Rig.ControlBoard.IControlBoard cb, RegValve rv, double timePulseSec)
{
this.uniCB = uniCB;
if (this.uniCB == null) throw new ArgumentNullException("ctrlBoard");
controlBoard = cb as TBF.Rig.ControlBoard.Uni.UniCB;
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
this.regV = regV as RegValve;
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Uni");
regulValveNr = this.regV.Idx1;
regulValve = rv as RegValve;
if (regulValve == null) throw new ArgumentNullException("regValve is null or not Elde");
regulValveNr = this.regulValve.Idx1;
this.timePulseSec = timePulseSec;
@@ -50,7 +49,13 @@ namespace TBF.Rig.Uni.RegValve
/// <summary>Start this operation</summary>
public void Start()
{
uniCB.RegVlvIncrMove(false, regulValveNr, timePulseSec);
//double positionPct = controlBoard.RValvePosition(regulValveNr);
//log.WarnFormat("RV#={0}, actPos={1}%", regulValveNr, positionPct.ToString("F1"));
//controlBoard.ValveMove(regulValveNr,
// TBF.Rig.ControlBoard.Legacy.RegulValveMode.PulseWidth,
// new double[2] { timePulseSec, timePulseSec },
// regulValve.StableTime);
}
/// <summary>Run this operation</summary>
@@ -59,6 +64,9 @@ namespace TBF.Rig.Uni.RegValve
/// </returns>
public Event Run()
{
//float positionPct = controlBoard.RValvePosition(regulValveNr);
//log.WarnFormat("RV#={0}, actPos={1}%", regulValveNr, positionPct.ToString("F1"));
return Event.PositionReached;
}
+1 -1
View File
@@ -1,5 +1,5 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.Generic;
+1 -1
View File
@@ -1,5 +1,5 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
/// Copyright (c) 2021 Sensus Metering Systems
///
using System;
using log4net;
+33 -25
View File
@@ -20,10 +20,11 @@ namespace TBF.Rig.Uni.RegValve
return string.Format("SetFlowOp({0}, Qfrom={1}, Qto={2})", regV.Name, shrinkedTgtFlowLo, shrinkedTgtFlowHi);
}
public const double RqrdFlowRangeRatio = 0.5;
///
/// Set by the constructor
/// Set by the constructor
///
readonly UniCB uniCB;
readonly RegValve regV;
@@ -36,8 +37,8 @@ namespace TBF.Rig.Uni.RegValve
readonly bool leaveFlowControlRunning;
readonly double maximalFlow;
///
///
/// Internal state of this operation
///
enum OpState
@@ -56,12 +57,13 @@ namespace TBF.Rig.Uni.RegValve
double currentReqFlowLo;
double currentReqFlowHi;
double targetPositionLo;
double targetPositionHi;
double targetPositionLo;
double targetPositionHi;
int startTime;
int setFlowTime;
int expireTime;
DoubleBox msrdFlow;
DoubleBox flowBox;
int isFlowOkDuration;
@@ -70,23 +72,23 @@ namespace TBF.Rig.Uni.RegValve
/// Events: FlowSet, FlowTimeOut
/// </summary>
/// <param name="uniCB">Control board device</param>
/// <param name="regValve">Regulation valve component</param>
/// <param name="regulValve">Regulation valve component</param>
/// <param name="flowMeter">Flowmeter component</param>
/// <param name="qFrom">Lower limit of the flow to be achieved in [m3/h]</param>
/// <param name="qTo">Upper limit of the flow to be achieved in [m3/h]</param>
/// <param name="msrdFlow">DoubleBox for measured flow</param>
/// <param name="pidCoef">PID coefficient (float)</param>
/// <param name="timeout">Timeout for the flow setting in [s]</param>
/// <param name="delay">Flow setting starts after this delay in [s]</param>
/// <param name="delay">Flow setting starts after this delay [s]</param>
/// <param name="leaveFlowControlRunning">true = Leave the measurement running after op. stop</param>
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
public SetFlowOp(UniCB uniCB, IRegValve regValve, IFlowMeter flowMeter, double qFrom, double qTo, DoubleBox msrdFlow,
public SetFlowOp(UniCB uniCB, IRegValve regValve, IFlowMeter flowMeter, double qFrom, double qTo, DoubleBox flowBox,
int timeout, int delay, bool leaveFlowControlRunning)
{
this.uniCB = uniCB;
if (this.uniCB == null) throw new ArgumentNullException("Control board is null or not Uni");
this.uniCB = uniCB;
if (this.uniCB == null) throw new ArgumentNullException("cBoard is null or not Uni");
this.regV = regValve as RegValve;
if (this.regV == null) throw new ArgumentNullException(string.Format("{0} is not Uni.RegValve", regValve.Name));
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Uni");
this.flowMeter = flowMeter;
if (this.flowMeter == null) throw new ArgumentNullException("flowMeter");
@@ -96,14 +98,15 @@ namespace TBF.Rig.Uni.RegValve
double rqrdFlowLoBeforeCorr = qFrom - MeasurementCorrection.GetCorrection(qFrom, flowMeter.Corrections);
double rqrdFlowHiBeforeCorr = qTo - MeasurementCorrection.GetCorrection(qTo, flowMeter.Corrections);
targetFlowAve = (rqrdFlowLoBeforeCorr + rqrdFlowHiBeforeCorr) / 2;
shrinkedTgtFlowLo = (RqrdFlowRangeRatio * rqrdFlowLoBeforeCorr)
+ ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the lower limit 15% of the range up
shrinkedTgtFlowHi = (RqrdFlowRangeRatio * rqrdFlowHiBeforeCorr)
+ ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the upper limit 15% of the range down
shrinkedTgtFlowLo = (RqrdFlowRangeRatio * rqrdFlowLoBeforeCorr) + ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the lower limit 15% of the range up
shrinkedTgtFlowHi = (RqrdFlowRangeRatio * rqrdFlowHiBeforeCorr) + ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the upper limit 15% of the range down
this.flowBox = flowBox;
if (this.flowBox == null) throw new ArgumentNullException("flowBox");
this.msrdFlow = msrdFlow;
this.timeout = timeout;
this.delay = delay;
this.leaveFlowControlRunning = leaveFlowControlRunning;
log.Debug(this.ToString());
@@ -169,13 +172,16 @@ namespace TBF.Rig.Uni.RegValve
return;
}
/// <summary>Start this operation</summary>
/// <summary>
/// Start this operation
/// </summary>
public void Start()
{
log.InfoFormat("SetFlowOp:Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regV.Idx1, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi);
/// Store the current time, etc.
startTime = StateMachine.Time;
setFlowTime = StateMachine.Time + delay;
expireTime = StateMachine.Time + timeout;
if (expireTime < 0) expireTime = int.MaxValue;
@@ -273,16 +279,17 @@ namespace TBF.Rig.Uni.RegValve
///
double frequency = flowMeter.ReadFrequency();
double flow = flowMeter.ReadFlow();
if (msrdFlow != null && flow != 0) msrdFlow.Val = flow;
if (flow != 0) flowBox.Val = flow;
if (currentReqFlowLo <= flow && flow <= currentReqFlowHi)
if ((currentReqFlowLo <= flow) && (flow <= currentReqFlowHi))
{
isFlowOkDuration++; /// Increment the flow within range duration
/// Flow is within range
isFlowOkDuration++;
if (isFlowOkDuration >= regV.FlowStableSec)
{
/// Flow is within range for sufficiently long time
if (regV.StoredPositionReuse)
if (regV.regValveCfg.StoredPositionReuse)
{
double rvPosition = regV.Position; /// Read the current position
double storedPosition;
@@ -329,12 +336,13 @@ namespace TBF.Rig.Uni.RegValve
}
}
/// <summary>Stop this operation</summary>
/// <summary>Start this operation</summary>
public void Stop()
{
if (!leaveFlowControlRunning)
{
uniCB.StopFlowControl(false, regV.Idx1); /// Stop the flow measurement
/// Stop flow measurement
uniCB.StopFlowControl(false, regV.Idx1);
}
opState = OpState.Idle;
@@ -14,7 +14,9 @@ using log4net;
using NHibernate.Util;
using TBF.Resources;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
using TBF.Rig.RegisterReaders.iPerlReaderUNI;
using TBF.Rig.RegisterReaders.PoseidonReader;
using TBF.Rig.Sequences;
@@ -157,6 +159,14 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
correctionsList.Add(new PoseidonCorrections(this,log, rfidDataLogger, componentBase, cfg, tests, multiTestParams));
continue;
}
if (smartHead is GenesisSmartReader genSmartReader)
{
if (correctionsList.Any(x => x is GenesisSmartReader))
continue;
correctionsList.Add(new GenesisCorrections( this,componentBase, cfg, tests, multiTestParams));
continue;
}
throw new Exception("Unknown smart head type");
}
@@ -189,6 +199,14 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
correctionsList.Add(new PoseidonCorrections(form));
continue;
}
if (smartHead is GenesisSmartReader genSmartReader)
{
if (correctionsList.Any(x => x is GenesisSmartReader))
continue;
correctionsList.Add(new GenesisCorrections(form));
continue;
}
throw new Exception("Unknown smart head type");
}
@@ -223,6 +241,12 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
typeReaders.Add(smartReader.ClassName);
continue;
}
if (smartHead is GenesisSmartReader genSmartReader)
{
typeReaders.Add(genSmartReader.ClassName);
continue;
}
throw new Exception("Unknown smart head type");
}
@@ -327,7 +351,13 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
{
checkBoxesEditMode = false;
ITestMethodCfg cfg = (componentBase as ITestMethodCfg);
ITestMethodSmart smart = (componentBase as ITestMethodSmart);
ITestMethodCfg cfg = (componentBase as ITestMethodCfg);
if (smart != null && cfg == null)
{
cfg = (componentBase.Cfg as ITestMethodCfg);
}
ISmartTestMethod smartTestMethod = componentBase as ISmartTestMethod;
//TODO get corrections based on defined meter
@@ -410,7 +440,8 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
if (iperlHeads == null) iperlHeads = new List<ISmartReader>();
waterMeterPositions0?.Clear();
if (waterMeterPositions0 == null) waterMeterPositions0 = new List<int>();
//iperlHeads = ProcessData.SmartHeadsUni;
//TODO BUMI check
iperlHeads = ProcessData.SmartHeadsUni;
string comparedTypeReader = SelectedTypeReader;
if (string.IsNullOrEmpty(SelectedTypeReader))
{
@@ -460,25 +491,47 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
private void InitializeMeterTypeItems()
{
if (_corrections.Count >= 0)
meterTypeComboBox.Items.Clear();
if (_corrections == null || _corrections.Count == 0)
{
meterTypeComboBox.Items.Clear();
int iItem = 0;
foreach (ICorrections correction in _corrections)
{
string name = correction?.TypeIdentificatorName();
if (string.IsNullOrEmpty(name))
{
name = iItem.ToString();
}
meterTypeComboBox.Items.Add(name);
if (iItem == 0)
SelectedTypeReader = name;
iItem++;
}
meterTypeComboBox.Visible = true;
meterTypeComboBox.Enabled = true;
meterTypeComboBox.SelectedIndex = 0;
meterTypeComboBox.Visible = false;
meterTypeComboBox.Enabled = false;
SelectedTypeReader = null;
return;
}
int iItem = 0;
foreach (ICorrections correction in _corrections)
{
string name = correction?.TypeIdentificatorName();
if (string.IsNullOrEmpty(name))
name = iItem.ToString();
meterTypeComboBox.Items.Add(name);
if (iItem == 0)
SelectedTypeReader = name;
iItem++;
}
meterTypeComboBox.Visible = true;
meterTypeComboBox.Enabled = true;
initializingMeterTypes = true;
try
{
// fill items...
if (meterTypeComboBox.Items.Count > 0)
meterTypeComboBox.SelectedIndex = 0;
}
finally
{
initializingMeterTypes = false;
}
}
@@ -491,7 +544,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
WaterMetersCount = iperlHeads.Count;
ShuffleTextBoxes(WaterMetersCount, ProcessData.LineSize);
Correction.PrepareForTestsActivities(WaterMetersCount);
Correction?.PrepareForTestsActivities(WaterMetersCount);
}
/// <summary>
@@ -530,7 +583,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
private void DoOnCommCompleted(object sender, CommCompletedEventArgs data)
{
Correction.DoOnCommCompleted(sender, data, waterMeterPositions0);
Correction?.DoOnCommCompleted(sender, data, waterMeterPositions0);
}
@@ -572,7 +625,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
textBoxesCount = wmsCount;
}
int count = checkBoxesEditMode ? textBoxesCount : Math.Min(textBoxesCount, Correction.GetHeadsCount());
int count = checkBoxesEditMode ? textBoxesCount : Math.Min(textBoxesCount, Correction?.GetHeadsCount() ?? 0);
for (int j = 0; j < count; j++)
{
labels[j].Text = (j + 1).ToString();
@@ -674,11 +727,15 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
samplePictureBox3.Visible = false;
}
if (_corrections.Count > 0)//enable combo for choose SmartMeter
if (_corrections != null && _corrections.Count > 0)
{
meterTypeComboBox.Visible = true;
}
Correction.Load(labels,counters,messages,checkBoxes,ckbIndex,ckbState, iperlHeads,textBoxesCount,checkBoxesEditMode );
else
{
meterTypeComboBox.Visible = false;
}
Correction?.Load(labels,counters,messages,checkBoxes,ckbIndex,ckbState, iperlHeads,textBoxesCount,checkBoxesEditMode );
///
/// Set location and checkbox states to values stored in local settings
@@ -693,7 +750,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
/// Regular activity (not a checkbox edit mode invoked from TBF menu)
/// Reset opto-data indication
for (int i = 0; i < Correction.GetHeadsCount(); i++)
for (int i = 0; i < (Correction?.GetHeadsCount() ?? 0); i++)
{
counters[i].BackColor = iPerlCommunicationConstants.OptoNokColor;
}
@@ -702,11 +759,14 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
//currentGroup++;
int wtId = 0;
foreach (var wt in Correction.GetAllThreads())
{
wt.Start(new Boxes.IntBox(wtId++)); /// Start worker threads !!!
}
}
if (Correction?.GetAllThreads() != null)
{
foreach (var wt in Correction?.GetAllThreads())
{
wt.Start(new Boxes.IntBox(wtId++)); /// Start worker threads !!!
}
}
}
}
@@ -917,13 +977,32 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
}
private bool initializingMeterTypes;
private void meterTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (initializingMeterTypes)
return;
ComboBox senderCombo = sender as ComboBox;
if (senderCombo == null) return;
if (senderCombo == null)
return;
SelectedTypeReader = senderCombo.SelectedItem?.ToString();
UpdateHeads();
SmartCommunicationForm_Load(this, EventArgs.Empty);
Correction?.Load(
labels,
counters,
messages,
checkBoxes,
ckbIndex,
ckbState,
iperlHeads,
textBoxesCount,
checkBoxesEditMode
);
}
}
}
+40 -8
View File
@@ -71,7 +71,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;CAMERA;LANG_PL;IPERL;</DefineConstants>
<DefineConstants>TRACE;CAMERA;LANG_PL;IPERL;LIVELOGDIAG_FlowMeter_cs;LIVELOGDIAG_RegValve_cs</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -1049,7 +1049,9 @@
<Compile Include="Rig\Operations\LargeMessageBoxOp.cs" />
<Compile Include="Rig\Operations\ReturnGivenEventOp.cs" />
<Compile Include="Rig\Output\DB\DatabaseWriter\Factory.cs" />
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.cs" />
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\Output\DB\DatabaseWriter\WriteDBCfgCtrl.designer.cs" />
<Compile Include="Rig\Output\DB\DatabaseWriter\WriterCfg.cs" />
<Compile Include="Rig\Output\DB\DatabaseWriter\WritingToDB.cs" />
@@ -1386,12 +1388,16 @@
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Utils\SerialDriver.cs" />
<Compile Include="Rig\RegisterReaders\GenesisRegReader\communication\Utils\SerialDriverBuilder.cs" />
<Compile Include="Rig\RegisterReaders\GenesisRegReader\Factory.cs" />
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisHeadTestCtrl.cs" />
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisHeadTestCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisHeadTestCtrl.Designer.cs">
<DependentUpon>GenesisHeadTestCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfg.cs" />
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfgCtrl.cs" />
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfgCtrl.designer.cs">
<DependentUpon>GenesisCfgCtrl.cs</DependentUpon>
</Compile>
@@ -1410,9 +1416,13 @@
<Compile Include="Rig\RegisterReaders\iPerlASICReader\Factory.cs" />
<Compile Include="Rig\RegisterReaders\iPerlASICReader\implementations\IPerlASICImplHeadTestCtrl.cs" />
<Compile Include="Rig\RegisterReaders\iPerlASICReader\implementations\SmartReader.cs" />
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IperlASICUniHeadTestCtrl.cs" />
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IperlASICUniHeadTestCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IperlASICUniHeadTestCtrl.Designer.cs" />
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IPerlUniCfgCtrl.cs" />
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IPerlUniCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\RegisterReaders\iPerlASICReader\IPerlUniCfgCtrl.designer.cs" />
<Compile Include="Rig\RegisterReaders\iPerlReaderUNI\common\IUniHeadTestCtrl.cs" />
<Compile Include="Rig\RegisterReaders\iPerlReaderUNI\Factory.cs" />
@@ -1484,6 +1494,8 @@
<DependentUpon>RRCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunner.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliTaskInfo.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliTaskState.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\Factory.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\JsonDataFromPoseidon.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonCfg.cs" />
@@ -1715,12 +1727,26 @@
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\Factory.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHead.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfg.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfgCtrl.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfgCtrl.designer.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\OptoReceivedEventArgs.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\OptoTelegramRaw.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\ProcParams.cs" />
<Compile Include="Rig\TestMethods\GenesisCommunication\GenesisHead\StatusStruct.cs" />
<Compile Include="Rig\TestMethods\GenesisFullCommunication\Factory.cs" />
<Compile Include="Rig\TestMethods\GenesisFullCommunication\GenesisCommunicationSeq.cs" />
<Compile Include="Rig\TestMethods\GenesisFullCommunication\GenesisCommunicationParams.cs" />
<Compile Include="Rig\TestMethods\GenesisFullCommunication\SequenceConditionOp.cs" />
<Compile Include="Rig\TestMethods\GenesisFullCommunication\TestMethod.cs" />
<Compile Include="Rig\TestMethods\GenesisFullCommunication\TestMethodCfg.cs" />
<Compile Include="Rig\TestMethods\GenesisFullCommunication\TestMethodCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\TestMethods\GenesisFullCommunication\TestMethodCfgCtrl.designer.cs">
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\TestMethods\iPerlCommunication\AllCompletedEventArgs.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\CheckBoxImage.cs">
<SubType>Component</SubType>
@@ -1771,7 +1797,9 @@
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\Utils\ISerialDriver.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\Utils\SerialDriver.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\communication\Utils\SerialDriverBuilder.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationForm.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationForm.designer.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationParams.cs" />
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlCommunicationSeq.cs" />
@@ -2288,6 +2316,7 @@
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\common\ICorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\common\ISmartReader.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\EnumExtensions.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\GenesisCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\IPerlASICCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\IPerlCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\PoseidonCorrections.cs" />
@@ -3647,6 +3676,9 @@
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\TestMethods\GenesisCommunication\GenesisHead\GenesisHeadCfgCtrl.resx" />
<EmbeddedResource Include="Rig\TestMethods\GenesisFullCommunication\TestMethodCfgCtrl.resx">
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\TestMethods\GrabImage\GrabImageCfgCtrl.resx">
<DependentUpon>GrabImageCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
@@ -189,8 +189,16 @@ namespace TBF.UI.Bench.Components
int extraWidth = splitContainer.Panel2.Width + 40;
int extraHeight = 80;
this.Width = desired.Width + extraWidth;
this.Height = desired.Height + extraHeight;
if (!desired.IsEmpty)
{
this.Width = desired.Width + extraWidth;
this.Height = desired.Height + extraHeight;
}
else
{
//this.Width += extraWidth;
//this.Height += extraHeight;
}
// Do not exceed screen working area
var screen = Screen.FromControl(this).WorkingArea;
@@ -43,7 +43,10 @@ namespace TBF.UI.Bench.Components
{
availCmpntsLstBox.SelectedIndex = selectedIndex;
}
}
/// SharedDlgSearchForListBox configuration
sharedSearchForListBox1.ListBoxEx = availCmpntsLstBox;
}
void Localize()
{
+2 -1
View File
@@ -1199,7 +1199,8 @@ namespace TBF.UI
private void optoHeadsToolStripMenuItem_Click(object sender, EventArgs e)
{
new iPerlCommunicationForm(true).ShowDialog();
//new iPerlCommunicationForm(true).ShowDialog();
new SmartCommunicationForm(true).ShowDialog();
}
private void statusStrip1_DoubleClick(object sender, EventArgs e)
+32 -2
View File
@@ -86,8 +86,38 @@ namespace TBF.UI.Process
Bridge.StateMachineTickHandler += delegate(object sndr, UiBridge.StateMachineTickEventArgs args)
{
if (InvokeRequired) { Invoke(new EventHandler<UiBridge.StateMachineTickEventArgs>(OnStateMachineTick), sndr, args); }
else OnStateMachineTick(sndr, args);
try
{
if (IsDisposed || Disposing || !IsHandleCreated)
{
return;
}
if (InvokeRequired)
{
BeginInvoke(new EventHandler<UiBridge.StateMachineTickEventArgs>(OnStateMachineTick), sndr, args);
}
else
{
OnStateMachineTick(sndr, args);
}
}
catch (ObjectDisposedException e)
{
log.DebugFormat("ProcessTabPageCtrl.OnStateMachineTick() skipped because control is disposed: {0}", e.Message);
}
catch (InvalidOperationException e)
{
log.DebugFormat("ProcessTabPageCtrl.OnStateMachineTick() skipped because UI is not available: {0}", e.Message);
}
catch (System.ComponentModel.InvalidAsynchronousStateException e)
{
log.DebugFormat("ProcessTabPageCtrl.OnStateMachineTick() skipped because UI thread is no longer available: {0}", e.Message);
}
catch (Exception e)
{
log.ErrorFormat("ProcessTabPageCtrl.OnStateMachineTick() failed: {0}", e.Message);
}
};
Bridge.TestCompletedHandler += delegate(object sender, TestCompletedEventArgs args)
@@ -2,6 +2,7 @@ using System;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.RegisterReaders.GenesisRegReader;
using TBF.Rig.RegisterReaders.GenesisRegReader.common;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication;
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
@@ -14,10 +15,16 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
public class GenesisReaderTests
{
private static GenesisCfg CreateCfg()
{
Factory factory = new Factory();
return new GenesisCfg(factory);
}
[TestMethod]
public void Debug_ProcessOptoLine_FormatVariants()
{
var reader = new GenesisSmartReader();
var reader = new GenesisSmartReader(CreateCfg());
InitializeReaderForTest(reader);
string[] variants =
@@ -28,26 +35,28 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
"@he \t1\t0\t0A1F59C4\t00017A43\t00115C45\t72E1596B\t00000400\t00001998\t7D91B652\t7D4F37E6\t000191E6\t0C\t062E4A9C\t5331"
};
int[] counts = new int[variants.Length];
for (int i = 0; i < variants.Length; i++)
{
bool blockCompleted = false;
reader.ProcessOptoLine(variants[i], DataStreamState.ProcessAndSave, out blockCompleted);
int optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
counts[i] = GetPrivateField<int>(reader, "optoDataCount");
Console.WriteLine($"Variant {i}: {variants[i]}");
Console.WriteLine($" blockCompleted={blockCompleted}");
Console.WriteLine($" optoDataCount={optoDataCount}");
Console.WriteLine($" optoDataCount={counts[i]}");
Console.WriteLine("--------------------------------");
}
Assert.Fail("Inspect which variant, if any, is accepted.");
Assert.IsTrue(counts.Any(c => c > 0), "At least one telegram format variant should be accepted.");
}
[TestMethod]
public void RealInput_ShouldCalculate_StartEndVolumes_AndTimes()
public void RealInput_ShouldParseCalibrationTelegrams()
{
var reader = new GenesisSmartReader();
var reader = new GenesisSmartReader(CreateCfg());
InitializeReaderForTest(reader);
string[] realInputLines = LoadRealInputLines();
@@ -110,87 +119,33 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
Console.WriteLine($"Final firstValidIx = {firstValidIx}");
Console.WriteLine($"Final lastValidIx = {lastValidIx}");
if (processedCount <= 0)
{
Assert.Fail(
"No valid calibration telegrams were parsed.\n" +
"Check the following:\n" +
"1. exact telegram prefix (for example @h vs @he)\n" +
"2. exact separators (spaces vs tabs)\n" +
"3. exact CRC / checksum\n" +
"4. whether ProcessOptoLine expects a complete multi-line block format\n" +
"See test output for per-line diagnostics.");
}
Assert.AreEqual(3, processedCount, "Expected all 3 calibration telegrams to be parsed.");
Assert.AreEqual(0, firstValidIx);
Assert.AreEqual(2, lastValidIx);
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
Assert.IsNotNull(optoData);
Assert.AreEqual(0, optoData[0].IChannel());
Assert.AreEqual(1, optoData[1].IChannel());
Assert.AreEqual(2, optoData[2].IChannel());
// With only one telegram per channel, full start/end reconstruction is not expected yet.
reader.TestStartTelegramIx = firstValidIx;
reader.TestEndTelegramIx = lastValidIx;
Console.WriteLine("=== BEFORE POST PROCESSING ===");
Console.WriteLine($"TestStartTelegramIx = {reader.TestStartTelegramIx}");
Console.WriteLine($"TestEndTelegramIx = {reader.TestEndTelegramIx}");
InvokePrivate(reader, "AddTestStartEndMarksToData", new object[] { 0, 0 });
InvokePrivate(reader, "DataStreamPostProcessing");
InvokePrivate(reader, "PrepareCalculatedChannelData");
object[] markArgs = { 0, 0 };
try
{
InvokePrivate(reader, "AddTestStartEndMarksToData", markArgs);
Console.WriteLine("AddTestStartEndMarksToData OK");
InvokePrivate(reader, "DataStreamPostProcessing");
Console.WriteLine("DataStreamPostProcessing OK");
InvokePrivate(reader, "PrepareCalculatedChannelData");
Console.WriteLine("PrepareCalculatedChannelData OK");
}
catch (Exception ex)
{
Assert.Fail(
"Post-processing failed.\n" +
$"Exception: {ex.GetType().Name}: {ex.Message}\n" +
$"StackTrace:\n{ex.StackTrace}");
}
Console.WriteLine("=== CALCULATED VALUES ===");
Console.WriteLine($"NoSamples = {reader.NoSamples}");
Console.WriteLine($"VolumeLtrStart = {reader.VolumeLtrStart}");
Console.WriteLine($"VolumeLtrEnd = {reader.VolumeLtrEnd}");
Console.WriteLine($"TimestampSecStart = {reader.TimestampSecStart}");
Console.WriteLine($"TimestampSecEnd = {reader.TimestampSecEnd}");
Assert.IsFalse(double.IsNaN(reader.VolumeLtrStart), "VolumeLtrStart is NaN");
Assert.IsFalse(double.IsNaN(reader.VolumeLtrEnd), "VolumeLtrEnd is NaN");
Assert.IsFalse(double.IsNaN(reader.TimestampSecStart), "TimestampSecStart is NaN");
Assert.IsFalse(double.IsNaN(reader.TimestampSecEnd), "TimestampSecEnd is NaN");
Assert.IsTrue(reader.TimestampSecEnd >= reader.TimestampSecStart,
$"Timestamp ordering invalid: start={reader.TimestampSecStart}, end={reader.TimestampSecEnd}");
Assert.IsTrue(reader.VolumeLtrEnd >= reader.VolumeLtrStart,
$"Volume ordering invalid: start={reader.VolumeLtrStart}, end={reader.VolumeLtrEnd}");
// When parser input is finally correct, replace these expected values:
const double expectedVolumeStart = 0.0;
const double expectedVolumeEnd = 0.0;
const double expectedTimeStart = 0.0;
const double expectedTimeEnd = 0.0;
const double tolerance = 0.000001;
Console.WriteLine("=== EXPECTED VS ACTUAL ===");
Console.WriteLine($"expectedVolumeStart = {expectedVolumeStart}, actual = {reader.VolumeLtrStart}");
Console.WriteLine($"expectedVolumeEnd = {expectedVolumeEnd}, actual = {reader.VolumeLtrEnd}");
Console.WriteLine($"expectedTimeStart = {expectedTimeStart}, actual = {reader.TimestampSecStart}");
Console.WriteLine($"expectedTimeEnd = {expectedTimeEnd}, actual = {reader.TimestampSecEnd}");
Assert.AreEqual(expectedVolumeStart, reader.VolumeLtrStart, tolerance, "VolumeLtrStart mismatch");
Assert.AreEqual(expectedVolumeEnd, reader.VolumeLtrEnd, tolerance, "VolumeLtrEnd mismatch");
Assert.AreEqual(expectedTimeStart, reader.TimestampSecStart, tolerance, "TimestampSecStart mismatch");
Assert.AreEqual(expectedTimeEnd, reader.TimestampSecEnd, tolerance, "TimestampSecEnd mismatch");
Assert.IsTrue(reader.NoSamples,
"With only one telegram per channel, recalculated start/end samples should still be unavailable.");
}
[TestMethod]
public void RealInput_ShouldSupport_RolloverNormalization()
public void RealInput_ShouldParseRolloverInputLines()
{
var reader = new GenesisSmartReader();
var reader = new GenesisSmartReader(CreateCfg());
InitializeReaderForTest(reader);
string[] realInputLines = LoadRealInputLinesWithRollover();
@@ -211,29 +166,25 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
int finalOptoDataCount = GetPrivateField<int>(reader, "optoDataCount");
Assert.IsTrue(
finalOptoDataCount > 1,
"Need at least 2 valid telegrams. Check exact telegram format / CRC in LoadRealInputLinesWithRollover().");
reader.TestStartTelegramIx = 0;
reader.TestEndTelegramIx = finalOptoDataCount - 1;
object[] markArgs = { 0, 0 };
InvokePrivate(reader, "AddTestStartEndMarksToData", markArgs);
InvokePrivate(reader, "DataStreamPostProcessing");
InvokePrivate(reader, "PrepareCalculatedChannelData");
Console.WriteLine($"VolumeLtrStart={reader.VolumeLtrStart}");
Console.WriteLine($"VolumeLtrEnd={reader.VolumeLtrEnd}");
Console.WriteLine($"TimestampSecStart={reader.TimestampSecStart}");
Console.WriteLine($"TimestampSecEnd={reader.TimestampSecEnd}");
Assert.IsTrue(reader.TimestampSecEnd >= reader.TimestampSecStart,
"Normalized end time should be >= start time");
Assert.IsTrue(reader.VolumeLtrEnd >= reader.VolumeLtrStart,
"Normalized end volume should be >= start volume");
Assert.AreEqual(3, finalOptoDataCount,
"Expected all provided rollover input lines to be parsed as telegrams.");
}
[TestMethod]
public void PrepareCalculatedChannelDataSimulationForTest_ShouldProduceUsableSamples()
{
var reader = new GenesisSmartReader(CreateCfg());
InitializeReaderForTest(reader);
reader.PrepareCalculatedChannelDataSimulationForTest();
Assert.IsFalse(reader.NoSamples);
Assert.AreEqual(105.0, reader.VolumeLtrStartAverage, 0.0001);
Assert.AreEqual(157.0, reader.VolumeLtrEndAwerage, 0.0001);
Assert.AreEqual(10.0, reader.TimestampSecStart, 0.0001);
Assert.AreEqual(20.0, reader.TimestampSecEnd, 0.0001);
}
private static void InitializeReaderForTest(GenesisSmartReader reader)
{
const int channelCount = 3;
@@ -264,6 +215,8 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
SetPrivateField(reader, "partOfTelegram", string.Empty);
SetPrivateField(reader, "startDataProcessing", true);
reader.StopQueueData = false;
reader.TestStartTelegramIx = 0;
reader.TestEndTelegramIx = 0;
}
@@ -133,13 +133,13 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
InvokePrepareCalculatedChannelData(reader);
Assert.AreEqual(200.666666666667, reader.VolumeLtrStart, 1e-9);
Assert.AreEqual(219.0, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(219.666666666667, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(1.0, reader.TimestampSecStart, 1e-9);
Assert.AreEqual(20.0, reader.TimestampSecEnd, 1e-9);
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartRaw, 1e-9);
Assert.AreEqual(219.0, reader.VolumeLtrEndRaw, 1e-9);
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartAverage, 1e-9);
Assert.AreEqual(219.666666666667, reader.VolumeLtrEndAwerage, 1e-9);
}
[TestMethod]
@@ -162,11 +162,6 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
index++;
}
// channel 1 loses its last two valid records
// valid ch1 becomes: 200..207 with timestamps 1..8
// longest channel deltaTime is 9 (channels 0 and 2)
// ch1 deltaVolume = 7, deltaTime = 7 => recalculated deltaVolume = 7 * 9 / 7 = 9
// recalculated end ch1 = 200 + 9 = 209
optoData[25].Flags = OptoTelegramFlags.InvalidTelegram;
optoData[28].Flags = OptoTelegramFlags.InvalidTelegram;
@@ -177,14 +172,14 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
InvokePrepareCalculatedChannelData(reader);
Assert.AreEqual(200.666666666667, reader.VolumeLtrStart, 1e-9);
Assert.AreEqual(208.33333333333334, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(208.33333333333334, reader.VolumeLtrEndRaw, 1e-9);
Assert.AreEqual(209.666666666667, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(209.666666666667, reader.VolumeLtrEndAwerage, 1e-9);
Assert.AreEqual(101.0, reader.VolumeLtrStartCh1, 1e-9);
Assert.AreEqual(201.0, reader.VolumeLtrStartCh2, 1e-9);
Assert.AreEqual(300.0, reader.VolumeLtrStartCh3, 1e-9);
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartRaw, 1e-9);
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartAverage, 1e-9);
Assert.AreEqual(110.0, reader.VolumeLtrEndCh1, 1e-9);
Assert.AreEqual(210.0, reader.VolumeLtrEndCh2, 1e-9);
@@ -272,24 +267,13 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
Assert.AreEqual(20.0, reader.TimestampSecEndCh2, 1e-9);
Assert.AreEqual(20.0, reader.TimestampSecEndCh3, 1e-9);
Assert.AreEqual(101.0, reader.VolumeLtrStartCh1, 1e-9);
Assert.AreEqual(201.0, reader.VolumeLtrStartCh2, 1e-9);
Assert.AreEqual(300.0, reader.VolumeLtrStartCh3, 1e-9);
Assert.AreEqual(219.0, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(219.666666666667, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(1.0, reader.TimestampSecStart, 1e-9);
Assert.AreEqual(20.0, reader.TimestampSecEnd, 1e-9);
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartRaw, 1e-9);
Assert.AreEqual(219.0, reader.VolumeLtrEndRaw, 1e-9);
Assert.AreEqual(120.0, reader.VolumeLtrEndCh1, 1e-9);
Assert.AreEqual(220.0, reader.VolumeLtrEndCh2, 1e-9);
Assert.AreEqual(319.0, reader.VolumeLtrEndCh3, 1e-9);
Assert.AreEqual(219.0, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(219.0, reader.VolumeLtrEndRaw, 1e-9);
Assert.AreEqual(200.666666666667, reader.VolumeLtrStartAverage, 1e-9);
Assert.AreEqual(219.666666666667, reader.VolumeLtrEndAwerage, 1e-9);
}
[TestMethod]
@@ -313,7 +297,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
InvokePrepareCalculatedChannelData(reader);
Assert.AreEqual(15.5, reader.VolumeLtrStart, 1e-9);
Assert.AreEqual(19.0, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(19.5, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(11.0, reader.VolumeLtrStartCh1, 1e-9);
Assert.AreEqual(20.0, reader.VolumeLtrStartCh2, 1e-9);
@@ -1,6 +1,8 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.Generic;
using TBF.Rig.RegisterReaders.GenesisRegReader;
using TBF.Rig.RegisterReaders.GenesisRegReader.common;
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
@@ -36,6 +38,15 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
return (T)field.GetValue(target);
}
private static void WaitForStopToFinish(GenesisSmartReader reader, int timeoutMs = 3000)
{
var stopTask = GetPrivateField<Task>(reader, "_backgroundStopTask");
if (stopTask != null)
{
stopTask.Wait(timeoutMs);
}
}
private static OptoTelegramRaw CreateOptoRecord(int channel, double volumeRawExt, double timestampExt)
{
return new OptoTelegramRaw
@@ -87,11 +98,10 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
Assert.AreEqual(DataStreamState.Flush, finalState, "Stop() should finish in Flush state.");
Assert.IsFalse(fake.IsOpen, "Serial port should be closed by Stop().");
// These values are populated only if DataStreamPostProcessing() ran.
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartRaw, 1e-9,
"Expected post-processing to prepare raw start values.");
Assert.AreEqual((15.0 + 25.0 + 35.0) / 3.0, reader.VolumeLtrEndRaw, 1e-9,
"Expected post-processing to prepare raw end values.");
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartAverage, 1e-9,
"Expected post-processing to prepare raw/recalculated start values.");
Assert.AreEqual((15.0 + 25.0 + 36.0) / 3.0, reader.VolumeLtrEndAwerage, 1e-9,
"Expected post-processing to prepare recalculated end values.");
}
[TestMethod]
@@ -111,6 +121,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.optoSerialPort = fake;
reader.Stop();
WaitForStopToFinish(reader);
var finalState = GetPrivateField<DataStreamState>(reader, "dataStreamState");
var stopQueueData = GetPrivateField<bool>(reader, "_stopQueueData");
@@ -119,10 +130,9 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
Assert.IsTrue(stopQueueData, "Immediate stop path should stop queueing.");
Assert.IsFalse(fake.IsOpen, "Serial port should be closed by Stop().");
// Should still be default because DataStreamPostProcessing() must NOT run.
Assert.AreEqual(0.0, reader.VolumeLtrStartRaw, 1e-9,
Assert.AreEqual(0.0, reader.VolumeLtrStartAverage, 1e-9,
"Post-processing should not run when previous state was ProcessAndSave.");
Assert.AreEqual(0.0, reader.VolumeLtrEndRaw, 1e-9,
Assert.AreEqual(0.0, reader.VolumeLtrEndAwerage, 1e-9,
"Post-processing should not run when previous state was ProcessAndSave.");
}
@@ -79,6 +79,15 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.StopQueueData = false;
}
private static void WaitForStopToFinish(GenesisSmartReader reader, int timeoutMs = 3000)
{
var stopTask = GetPrivateField<Task>(reader, "_backgroundStopTask");
if (stopTask != null)
{
stopTask.Wait(timeoutMs);
}
}
[TestMethod]
public void Start_ShouldOpenPort_AndEnableProcessing()
{
@@ -129,9 +138,10 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.TestEndTelegramIx = 1;
reader.Stop();
WaitForStopToFinish(reader);
Assert.IsFalse(fake.IsOpen);
Assert.AreEqual(2, fake.CloseCalls);
Assert.IsTrue(fake.CloseCalls >= 1);
}
@@ -165,6 +175,9 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.Initialize();
reader.optoSerialPort = fake;
InitializeThreeChannelState(reader);
EnableProcessingLoopForTests(reader);
bool reset;
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", DataStreamState.ProcessAndSave, out reset);
@@ -199,6 +212,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.optoSerialPort = fake;
InitializeThreeChannelState(reader);
EnableProcessingLoopForTests(reader);
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out bool resetDataBuffer);
@@ -254,6 +268,7 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.optoSerialPort = fake;
InitializeThreeChannelState(reader);
EnableProcessingLoopForTests(reader);
var line =
"@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD";
@@ -265,9 +280,15 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
}
[DataTestMethod]
[DataRow("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", 0)]
[DataRow("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD", 1)]
[DataRow("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", 2)]
[DataRow(
"@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
0)]
[DataRow(
"@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD",
1)]
[DataRow(
"@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E",
2)]
public void ProcessOptoLine_ShouldInsertTelegramAndUpdateExpectedChannel(string line, int expectedChannelIndex)
{
var fake = new FakeSerialDriver();
@@ -277,6 +298,9 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.Initialize();
reader.optoSerialPort = fake;
InitializeThreeChannelState(reader);
EnableProcessingLoopForTests(reader);
reader.ProcessOptoLine(line, DataStreamState.ProcessAndSave, out bool resetDataBuffer);
var volumeRawExtLast = GetPrivateField<double[]>(reader, "volumeRawExtLast");
@@ -284,27 +308,25 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
var optoDataCount = GetPrivateField<int>(reader, "optoDataCount");
Assert.AreEqual(1, optoDataCount, "Exactly one telegram should be inserted.");
Assert.AreEqual(1, optoDataCount);
var inserted = optoData[0];
Assert.IsNotNull(inserted, "Inserted telegram should not be null.");
Assert.IsNotNull(inserted);
Assert.AreEqual(expectedChannelIndex, inserted.IChannel(), "Inserted telegram channel does not match expected channel.");
Assert.AreEqual(0, inserted.Counter, "First inserted telegram should have counter 0.");
Assert.AreEqual(OptoTelegramFlags.OK, inserted.Flags, "Inserted telegram should be marked OK.");
Assert.AreNotEqual(default(DateTime), inserted.DateTime, "Inserted telegram DateTime should be initialized.");
Assert.AreEqual(expectedChannelIndex, inserted.IChannel());
Assert.AreEqual(0, inserted.Counter);
Assert.AreEqual(OptoTelegramFlags.OK, inserted.Flags);
Assert.AreNotEqual(0.0, inserted.VolumeRaw, "Inserted telegram VolumeRaw should be set.");
Assert.AreNotEqual(0.0, inserted.VolumeRawExt, "Inserted telegram VolumeRawExt should be set.");
Assert.AreNotEqual(0.0, inserted.Timestamp, "Inserted telegram Timestamp should be set.");
Assert.AreNotEqual(0.0, inserted.TimestampExt, "Inserted telegram TimestampExt should be set.");
Assert.AreNotEqual(0.0, inserted.VolumeRawExt);
Assert.AreNotEqual(0.0, inserted.TimestampExt);
for (int i = 0; i < ChannelCount; i++)
{
if (i == expectedChannelIndex)
{
Assert.AreNotEqual(0.0, volumeRawExtLast[i], $"Expected channel {i} volume cache was not updated.");
Assert.AreNotEqual(0.0, timestampExtLast[i], $"Expected channel {i} timestamp cache was not updated.");
Assert.AreNotEqual(0.0, timestampExtLast[i],
$"Expected channel {i} timestamp cache was not updated.");
}
else
{
@@ -313,11 +335,8 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
}
}
Assert.AreEqual(volumeRawExtLast[expectedChannelIndex], inserted.VolumeRawExt, 1e-9,
"Inserted telegram VolumeRawExt should match updated channel cache.");
Assert.AreEqual(timestampExtLast[expectedChannelIndex], inserted.TimestampExt, 1e-9,
"Inserted telegram TimestampExt should match updated channel cache.");
Assert.AreEqual(volumeRawExtLast[expectedChannelIndex], inserted.VolumeRawExt, 1e-9);
Assert.AreEqual(timestampExtLast[expectedChannelIndex], inserted.TimestampExt, 1e-9);
}
[TestMethod]
@@ -344,13 +363,16 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
InvokePrepareCalculatedChannelData(reader);
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStart, 1e-9);
Assert.AreEqual((15.0 + 25.0 + 35.0) / 3.0, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual((15.0 + 25.0 + 36.0) / 3.0, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(100.0, reader.TimestampSecStart, 1e-9);
Assert.AreEqual(105.0, reader.TimestampSecEnd, 1e-9);
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartRaw, 1e-9);
Assert.AreEqual((15.0 + 25.0 + 35.0) / 3.0, reader.VolumeLtrEndRaw, 1e-9);
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartAverage, 1e-9);
Assert.AreEqual((15.0 + 25.0 + 36.0) / 3.0, reader.VolumeLtrEndAwerage, 1e-9);
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartRawRaw, 1e-9);
Assert.AreEqual((15.0 + 25.0 + 35.0) / 3.0, reader.VolumeLtrEndRawRaw, 1e-9);
}
private static OptoTelegramRaw CreateOptoRecord(int channel, double volumeRawExt, double timestampExt)
@@ -388,7 +410,21 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
InvokePrepareCalculatedChannelData(reader);
Assert.AreEqual(15.5, reader.VolumeLtrStart, 1e-9);
Assert.AreEqual(19.0, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(19.5, reader.VolumeLtrEnd, 1e-9);
Assert.AreEqual(15.5, reader.VolumeLtrStartAverage, 1e-9);
Assert.AreEqual(19.5, reader.VolumeLtrEndAwerage, 1e-9);
Assert.AreEqual(15.5, reader.VolumeLtrStartRawRaw, 1e-9);
Assert.AreEqual(19.0, reader.VolumeLtrEndRawRaw, 1e-9);
Assert.AreEqual(11.0, reader.VolumeLtrStartRawCh1, 1e-9);
Assert.AreEqual(20.0, reader.VolumeLtrStartRawCh2, 1e-9);
Assert.AreEqual(0.0, reader.VolumeLtrStartRawCh3, 1e-9);
Assert.AreEqual(14.0, reader.VolumeLtrEndRawCh1, 1e-9);
Assert.AreEqual(24.0, reader.VolumeLtrEndRawCh2, 1e-9);
Assert.AreEqual(0.0, reader.VolumeLtrEndRawCh3, 1e-9);
}
[TestMethod]
@@ -425,39 +461,37 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
}
[TestMethod]
public void ReadOptoData_FullBlock_ShouldDiscardBuffersAfterClosingF()
public void ProcessingLoop_FullBlock_ShouldDiscardBuffersAfterClosingF()
{
var fake = new FakeSerialDriver();
fake.EnqueueLine("@f AA754B 4D0CEE78 5D89");
fake.EnqueueLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331");
fake.EnqueueLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD");
fake.EnqueueLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E");
fake.EnqueueLine("@f AA7C01 4D0CFE76 B08F");
fake.Open();
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
reader.Initialize();
fake.Open();
reader.optoSerialPort = fake;
reader.ResetAfterBlockRepetitions = 1;
var readMethod = typeof(GenesisSmartReader).GetMethod(
"ReadOptoData",
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new[] { typeof(DataStreamState) },
null);
InitializeThreeChannelState(reader);
EnableProcessingLoopForTests(reader);
Assert.IsNotNull(readMethod);
for (int i = 0; i < 5; i++)
reader.StartProcessingLoop();
try
{
readMethod.Invoke(reader, new object[] { DataStreamState.ProcessAndSave });
}
reader.TestEnqueueLine("@f AA754B 4D0CEE78 5D89");
reader.TestEnqueueLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331");
reader.TestEnqueueLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD");
reader.TestEnqueueLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E");
reader.TestEnqueueLine("@f AA7C01 4D0CFE76 B08F");
Assert.AreEqual(1, fake.DiscardInCalls, "Input buffer should be discarded once after completed block.");
Assert.AreEqual(1, fake.DiscardOutCalls, "Output buffer should be discarded once after completed block.");
Thread.Sleep(300);
Assert.AreEqual(1, fake.DiscardInCalls, "Input buffer should be discarded once after completed block.");
Assert.AreEqual(1, fake.DiscardOutCalls, "Output buffer should be discarded once after completed block.");
}
finally
{
reader.StopProcessingLoop();
}
}
[TestMethod]
@@ -471,10 +505,13 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.optoSerialPort = fake;
reader.ResetAfterBlockRepetitions = 1;
InitializeThreeChannelState(reader);
EnableProcessingLoopForTests(reader);
bool reset;
reader.ProcessOptoLine("@f AA754B 4D0CEE78 5D89", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset, "Opening @f must not reset buffers.");
Assert.IsFalse(reset);
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset);
@@ -529,24 +566,24 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.optoSerialPort = fake;
reader.ResetAfterBlockRepetitions = 3;
InitializeThreeChannelState(reader);
EnableProcessingLoopForTests(reader);
bool reset;
for (int repetition = 1; repetition <= 3; repetition++)
{
reader.ProcessOptoLine("@f AA754B 4D0CEE78 5D89", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset, "Reset must not happen on opening @f, repetition " + repetition);
Assert.IsFalse(reset);
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset, "Reset must not happen after @h1, repetition " + repetition);
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset);
reader.ProcessOptoLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD",
DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset, "Reset must not happen after @h2, repetition " + repetition);
reader.ProcessOptoLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset);
reader.ProcessOptoLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E",
DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset, "Reset must not happen after @h3, repetition " + repetition);
reader.ProcessOptoLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset);
reader.ProcessOptoLine("@f AA7C01 4D0CFE76 B08F", DataStreamState.ProcessAndSave, out reset);
@@ -568,24 +605,24 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
reader.optoSerialPort = fake;
reader.ResetAfterBlockRepetitions = 5;
InitializeThreeChannelState(reader);
EnableProcessingLoopForTests(reader);
bool reset;
for (int repetition = 1; repetition <= 5; repetition++)
{
reader.ProcessOptoLine("@f AA754B 4D0CEE78 5D89", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset, "Reset must not happen on opening @f, repetition " + repetition);
Assert.IsFalse(reset);
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331",
DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset, "Reset must not happen after @h1, repetition " + repetition);
reader.ProcessOptoLine("@h 1 0 0A1F59C4 00017A43 00115C45 72E1596B 00000400 00001998 7D91B652 7D4F37E6 000191E6 0C 062E4A9C 5331", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset);
reader.ProcessOptoLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD",
DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset, "Reset must not happen after @h2, repetition " + repetition);
reader.ProcessOptoLine("@h 2 0 0A1B1FE8 00017B7F 00116B56 72B77427 00000400 0000199A 7DC09688 7B570006 000191E6 0C 062E5326 95BD", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset);
reader.ProcessOptoLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E",
DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset, "Reset must not happen after @h3, repetition " + repetition);
reader.ProcessOptoLine("@h 3 0 0A1DF1D5 00017EA8 00118037 741F80F3 00000400 00001998 7E58A62E 7CC2C606 000191E6 0C 062E5BAE D40E", DataStreamState.ProcessAndSave, out reset);
Assert.IsFalse(reset);
reader.ProcessOptoLine("@f AA7C01 4D0CFE76 B08F", DataStreamState.ProcessAndSave, out reset);
@@ -742,18 +779,12 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
Assert.AreEqual(20.0, sut.TimestampSecEndCh2, 0.0001);
Assert.AreEqual(20.0, sut.TimestampSecEndCh3, 0.0001);
Assert.AreEqual(105.0, sut.VolumeLtrStartRaw, 0.0001);
Assert.AreEqual(157.0, sut.VolumeLtrEndRaw, 0.0001);
Assert.AreEqual(105.0, sut.VolumeLtrStartAverage, 0.0001);
Assert.AreEqual(157.0, sut.VolumeLtrEndAwerage, 0.0001);
Assert.AreEqual(10.0, sut.TimestampSecStart, 0.0001);
Assert.AreEqual(20.0, sut.TimestampSecEnd, 0.0001);
}
[TestMethod]
public void METHOD()
{
}
}
}
@@ -10,22 +10,33 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
[TestClass]
public class GenesisSmartReader_Q3Test
{
private static readonly double[] ValidInitFactors = { 15625.0, 15625.0, 15625.0 };
[TestMethod]
public void GetQ3Calibration_ShouldReturnInvalid_WhenRawDataIsNull()
public void GetQ3Calibration_ShouldRemainInvalid_WhenRawDataIsNull()
{
var sut = new GenesisSmartReader();
InitializeReaderForQ3Test(sut);
SetPrivateField(sut, "_rawStartEndByChannel", null);
sut.GetQ3Calibration(refVolume: 1000.0, refTime: 120.0, initCalibFactor: 15625.0);
var valid = new bool[3];
var calib = new double[3];
sut.GetQ3Calibration(
refVolume: 1000.0,
refTime: 120.0,
initCalibFactor: ValidInitFactors,
ref valid,
ref calib);
Assert.IsFalse(sut.Q3CalibValid);
Assert.AreEqual(0.0, sut.Q3CalibValue, 0.000001);
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
}
[TestMethod]
public void GetQ3Calibration_ShouldReturnInvalid_WhenNoSamplesConditionIsTrue()
public void GetQ3Calibration_ShouldRemainInvalid_WhenNoSamplesIsTrue()
{
var sut = new GenesisSmartReader();
InitializeReaderForQ3Test(sut);
@@ -34,69 +45,255 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
Assert.IsTrue(sut.NoSamples, "Expected NoSamples to be true for this test.");
sut.GetQ3Calibration(refVolume: 1000.0, refTime: 120.0, initCalibFactor: 15625.0);
var valid = new bool[3];
var calib = new double[3];
sut.GetQ3Calibration(
refVolume: 1000.0,
refTime: 120.0,
initCalibFactor: ValidInitFactors,
ref valid,
ref calib);
Assert.IsFalse(sut.Q3CalibValid);
Assert.AreEqual(0.0, sut.Q3CalibValue, 0.000001);
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
}
[TestMethod]
public void GetQ3Calibration_ShouldReturnInvalid_WhenRefVolumeIsZero()
public void GetQ3Calibration_ShouldRemainInvalid_WhenRefVolumeIsZero()
{
var sut = new GenesisSmartReader();
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
Assert.IsFalse(sut.NoSamples);
Assert.IsFalse(sut.NoSamples, "Prepared data should produce valid samples.");
var valid = new bool[3];
var calib = new double[3];
sut.GetQ3Calibration(refVolume: 0.0, refTime: 120.0, initCalibFactor: 15625.0);
sut.GetQ3Calibration(
refVolume: 0.0,
refTime: 120.0,
initCalibFactor: ValidInitFactors,
ref valid,
ref calib);
Assert.IsFalse(sut.Q3CalibValid);
Assert.AreEqual(0.0, sut.Q3CalibValue, 0.000001);
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
}
[TestMethod]
public void GetQ3Calibration_ShouldReturnInvalid_WhenRefTimeIsZero()
public void GetQ3Calibration_ShouldRemainInvalid_WhenRefTimeIsZero()
{
var sut = new GenesisSmartReader();
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
Assert.IsFalse(sut.NoSamples);
Assert.IsFalse(sut.NoSamples, "Prepared data should produce valid samples.");
var valid = new bool[3];
var calib = new double[3];
sut.GetQ3Calibration(refVolume: 1000.0, refTime: 0.0, initCalibFactor: 15625.0);
sut.GetQ3Calibration(
refVolume: 1000.0,
refTime: 0.0,
initCalibFactor: ValidInitFactors,
ref valid,
ref calib);
Assert.IsFalse(sut.Q3CalibValid);
Assert.AreEqual(0.0, sut.Q3CalibValue, 0.000001);
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
}
[TestMethod]
public void GetQ3Calibration_ShouldReturnInvalid_WhenInitCalibFactorIsZero()
public void GetQ3Calibration_ShouldMarkInvalid_WhenInitFactorsAreZero()
{
var sut = new GenesisSmartReader();
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
Assert.IsFalse(sut.NoSamples);
Assert.IsFalse(sut.NoSamples, "Prepared data should produce valid samples.");
var init = new[] { 0.0, 0.0, 0.0 };
var valid = new bool[3];
var calib = new double[3];
sut.GetQ3Calibration(refVolume: 1000.0, refTime: 120.0, initCalibFactor: 0.0);
sut.GetQ3Calibration(
refVolume: 1000.0,
refTime: 120.0,
initCalibFactor: init,
ref valid,
ref calib);
Assert.IsFalse(sut.Q3CalibValid);
Assert.AreEqual(0.0, sut.Q3CalibValue, 0.000001);
CollectionAssert.AreEqual(new[] { false, false, false }, valid);
CollectionAssert.AreEqual(new[] { 0.0, 0.0, 0.0 }, calib);
}
[TestMethod]
public void GetQ3Calibration_ShouldProduceNonNegativeResult_WithPreparedSimulationData()
public void CalculateQ3Calibration_ShouldPopulatePerChannelValues_WithPreparedSimulationData()
{
var sut = new GenesisSmartReader();
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
InvokePrivateByName(sut, "SetQ3Calibration", new object[] { ValidInitFactors });
Assert.IsFalse(sut.NoSamples, "Prepared data should produce valid samples.");
Assert.IsFalse(sut.NoSamples);
sut.GetQ3Calibration(refVolume: 1.0, refTime: 120.0, initCalibFactor: 15625.0);
sut.CalculateQ3Calibration(200.0, 120.0);
Assert.IsTrue(sut.Q3CalibValue >= 0.0);
Assert.IsNotNull(sut.Q3CalibValue);
Assert.AreEqual(3, sut.Q3CalibValue.Length);
Assert.IsTrue(sut.Q3CalibValue.All(v => !Double.IsNaN(v)));
Assert.IsTrue(sut.Q3CalibValue.All(v => v >= 0.0));
}
[TestMethod]
public void GetQ3Calibration_ShouldCalculateExpectedValues_ForKnownInput()
{
var sut = new GenesisSmartReader();
var raw = CreateKnownStartEndData(
// start volume / end volume / start time / end time
(100.0, 150.0, 10.0, 20.0), // dV = 50, dT = 10
(105.0, 165.0, 10.0, 22.0), // dV = 60, dT = 12
(110.0, 180.0, 10.0, 25.0) // dV = 70, dT = 15
);
SetPrivateField(sut, "_rawStartEndByChannel", raw);
SetPrivateField(sut, "_recalculatedStartEndByChannel", raw); // important for NoSamples == false
SetPrivateField(sut, "optoDataCount", 2);
sut.TestStartTelegramIx = 0;
sut.TestEndTelegramIx = 1;
Assert.IsFalse(sut.NoSamples, "Expected prepared data to produce valid samples.");
var init = new[] { 15625.0, 15625.0, 15625.0 };
var valid = new bool[3];
var calib = new double[3];
sut.GetQ3Calibration(
refVolume: 200.0,
refTime: 120.0,
initCalibFactor: init,
ref valid,
ref calib);
double expectedCh1 = (200.0 / 600.0) * 15625.0;
double expectedCh2 = (200.0 / 600.0) * 15625.0;
double expectedCh3 = (200.0 / 560.0) * 15625.0;
Assert.AreEqual(expectedCh1, calib[0], 0.0001);
Assert.AreEqual(expectedCh2, calib[1], 0.0001);
Assert.AreEqual(expectedCh3, calib[2], 0.0001);
Assert.IsFalse(valid[0]);
Assert.IsFalse(valid[1]);
Assert.IsFalse(valid[2]);
}
[TestMethod]
public void GetQ3Calibration_ShouldMarkChannelValid_WhenDifferenceIsWithinFivePercent()
{
var sut = new GenesisSmartReader();
// We want recalculatedDeltaVolume == refVolume, so calculated factor == initial factor.
// refVolume = 200, refTime = 120
// choose dT = 10, dV = 16.6666666666667 => coef = 12 => recalculated dV = 200
var raw = CreateKnownStartEndData(
(100.0, 116.6666666666667, 10.0, 20.0),
(200.0, 216.6666666666667, 10.0, 20.0),
(300.0, 316.6666666666667, 10.0, 20.0)
);
SetPrivateField(sut, "_rawStartEndByChannel", raw);
SetPrivateField(sut, "_recalculatedStartEndByChannel", raw);
SetPrivateField(sut, "optoDataCount", 2);
sut.TestStartTelegramIx = 0;
sut.TestEndTelegramIx = 1;
Assert.IsFalse(sut.NoSamples, "Expected prepared data to produce valid samples.");
var init = new[] { 15625.0, 15625.0, 15625.0 };
var valid = new bool[3];
var calib = new double[3];
sut.GetQ3Calibration(
refVolume: 200.0,
refTime: 120.0,
initCalibFactor: init,
ref valid,
ref calib);
Assert.IsTrue(valid[0], $"Ch1 invalid, value={calib[0]}");
Assert.IsTrue(valid[1], $"Ch2 invalid, value={calib[1]}");
Assert.IsTrue(valid[2], $"Ch3 invalid, value={calib[2]}");
Assert.AreEqual(15625.0, calib[0], 0.001);
Assert.AreEqual(15625.0, calib[1], 0.001);
Assert.AreEqual(15625.0, calib[2], 0.001);
}
[TestMethod]
public void CalculateQ3Calibration_ShouldComputeExpectedChannelValues_FromSimulationData()
{
var sut = new GenesisSmartReader();
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
InvokePrivateByName(sut, "SetQ3Calibration", new object[] { ValidInitFactors });
sut.CalculateQ3Calibration(200.0, 120.0);
// initial values remain exposed through Q3CalibValue
Assert.AreEqual(15625.0, sut.Q3CalibValue[0], 0.000001);
Assert.AreEqual(15625.0, sut.Q3CalibValue[1], 0.000001);
Assert.AreEqual(15625.0, sut.Q3CalibValue[2], 0.000001);
// calculated values
Assert.AreEqual(5208.33333333333, sut.Q3Calib_Ch1Value, 0.000001);
Assert.AreEqual(5008.01282051282, sut.Q3Calib_Ch2Value, 0.000001);
Assert.AreEqual(4822.53086419753, sut.Q3Calib_Ch3Value, 0.000001);
}
[TestMethod]
public void CalculateQ3Calibration_ShouldKeepInitialArray_AndUpdateCalculatedChannelProperties()
{
var sut = new GenesisSmartReader();
InvokePrivateByName(sut, "PrepareCalculatedChannelDataForTest", true);
InvokePrivateByName(sut, "SetQ3Calibration", new object[] { ValidInitFactors });
sut.CalculateQ3Calibration(200.0, 120.0);
// Q3CalibValue currently exposes INITIAL calibration values, not calculated ones
Assert.AreEqual(15625.0, sut.Q3CalibValue[0], 0.000001);
Assert.AreEqual(15625.0, sut.Q3CalibValue[1], 0.000001);
Assert.AreEqual(15625.0, sut.Q3CalibValue[2], 0.000001);
// Per-channel public properties expose calculated values
Assert.IsTrue(sut.Q3Calib_Ch1Value > 0.0);
Assert.IsTrue(sut.Q3Calib_Ch2Value > 0.0);
Assert.IsTrue(sut.Q3Calib_Ch3Value > 0.0);
Assert.AreNotEqual(sut.Q3CalibValue[0], sut.Q3Calib_Ch1Value, 0.000001);
Assert.AreNotEqual(sut.Q3CalibValue[1], sut.Q3Calib_Ch2Value, 0.000001);
Assert.AreNotEqual(sut.Q3CalibValue[2], sut.Q3Calib_Ch3Value, 0.000001);
}
[TestMethod]
public void PrepareCalculatedChannelDataSimulationForTest_ShouldPrepareUsableData()
{
var sut = new GenesisSmartReader();
InvokePrivateByName(sut, "PrepareCalculatedChannelDataSimulationForTest");
Assert.IsFalse(sut.NoSamples);
Assert.IsTrue(sut.VolumeLtrStart >= 0.0);
Assert.IsTrue(sut.VolumeLtrEnd >= 0.0);
Assert.IsTrue(sut.TimestampSecEnd >= sut.TimestampSecStart);
}
private static void InitializeReaderForQ3Test(GenesisSmartReader reader)
@@ -115,20 +312,55 @@ namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
{
new[]
{
CreateRecord(0.0, 0.0),
CreateRecord(15625.0, 120.0)
CreateRecord(0.0, 0.0, 1),
CreateRecord(15625.0, 120.0, 1)
},
new OptoTelegramRaw[2],
new OptoTelegramRaw[2]
new[]
{
CreateRecord(0.0, 0.0, 2),
CreateRecord(15625.0, 120.0, 2)
},
new[]
{
CreateRecord(0.0, 0.0, 3),
CreateRecord(15625.0, 120.0, 3)
}
};
}
private static OptoTelegramRaw CreateRecord(double volumeRawExt, double timestampExt)
private static OptoTelegramRaw[][] CreateKnownStartEndData(
(double startVolume, double endVolume, double startTime, double endTime) ch1,
(double startVolume, double endVolume, double startTime, double endTime) ch2,
(double startVolume, double endVolume, double startTime, double endTime) ch3)
{
return new[]
{
new[]
{
CreateRecord(ch1.startVolume, ch1.startTime, 1),
CreateRecord(ch1.endVolume, ch1.endTime, 1)
},
new[]
{
CreateRecord(ch2.startVolume, ch2.startTime, 2),
CreateRecord(ch2.endVolume, ch2.endTime, 2)
},
new[]
{
CreateRecord(ch3.startVolume, ch3.startTime, 3),
CreateRecord(ch3.endVolume, ch3.endTime, 3)
}
};
}
private static OptoTelegramRaw CreateRecord(double volumeRawExt, double timestampExt, int channel)
{
return new OptoTelegramRaw
{
VolumeRawExt = volumeRawExt,
TimestampExt = timestampExt
TimestampExt = timestampExt,
iChannel = channel,
Flags = OptoTelegramFlags.OK
};
}
@@ -12,35 +12,36 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
[TestSubject(typeof(CliRunner))]
public class CliRunnerTest
{
[TestMethod]
public void ExtractJson_Test()
{
String allOutput = " {\n \"DeviceId\": \"1000000267\"\n}\n";
string allOutput = " {\n \"DeviceId\": \"1000000267\"\n}\n";
CliRunner cliRunner = new CliRunner(false);
string json = cliRunner.ExtractJson(allOutput);
Assert.IsTrue(!string.IsNullOrEmpty(json));
Assert.IsFalse(string.IsNullOrEmpty(json));
}
[TestMethod]
public void ExtractJson_Test2()
{
String allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
string allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
CliRunner cliRunner = new CliRunner(false);
string json = cliRunner.ExtractJson(allOutput);
Assert.IsTrue(!string.IsNullOrEmpty(json));
Assert.IsFalse(string.IsNullOrEmpty(json));
}
[TestMethod]
public void TryJsonStringDeserialize_Test()
{
String allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
string allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
CliRunner cliRunner = new CliRunner(false);
string json = cliRunner.ExtractJson(allOutput);
var ok = cliRunner.TryJsonStringDeserialize<JsonDataFromPoseidon>(json, out var dto);
bool ok = cliRunner.TryJsonStringDeserialize<JsonDataFromPoseidon>(json, out var dto);
Assert.IsTrue(ok, "Deserialization failed");
Assert.IsNotNull(dto);
Assert.AreEqual("1000000267", dto.DeviceId);
@@ -53,120 +54,165 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
[TestMethod]
public void RunMultipleTimesTestProgram_CheckParalelWork()
{
SerialPortData serialPort = new SerialPortData("COM3","cmdSleepTest.exe",74);
// Check if the executable exists in current directory
SerialPortData serialPort = new SerialPortData("COM3", "cmdSleepTest.exe", 74);
if (!System.IO.File.Exists(serialPort.SerialPortCmdClientPath))
{
Assert.Inconclusive($"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
Assert.Inconclusive(
$"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
return;
}
CliRunner cliRunner = new CliRunner(false);
CliRunner cliRunnerOne = new CliRunner(false);
DateTime StartTime = DateTime.Now;
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
DateTime startTime = DateTime.Now;
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
serialPort,
SerialPortData.EMeterArg.AllParams);
cliRunnerOne.WaitAll();
TimeSpan OneEndTime = DateTime.Now - StartTime;
StartTime = DateTime.Now;
Console.WriteLine($"Start Time Loop: {StartTime.ToString("yyyy-MM-dd HH:mm:ss")}");
TimeSpan oneEndTime = DateTime.Now - startTime;
startTime = DateTime.Now;
Console.WriteLine($"Start Time Loop: {startTime:yyyy-MM-dd HH:mm:ss}");
for (int i = 0; i < 100; i++)
{
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
serialPort,
SerialPortData.EMeterArg.AllParams);
}
cliRunner.WaitAll();
DateTime EndTime = DateTime.Now;
Console.WriteLine($"End Time Loop: {EndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
TimeSpan delta = EndTime - StartTime;
Console.WriteLine($"Delta Time One process {OneEndTime.Hours:D2}:{OneEndTime.Minutes:D2}:{OneEndTime.Seconds:D2}.{OneEndTime.Milliseconds:D3} " +
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
DateTime endTime = DateTime.Now;
Console.WriteLine($"End Time Loop: {endTime:yyyy-MM-dd HH:mm:ss}");
TimeSpan delta = endTime - startTime;
Console.WriteLine(
$"Delta Time One process {oneEndTime.Hours:D2}:{oneEndTime.Minutes:D2}:{oneEndTime.Seconds:D2}.{oneEndTime.Milliseconds:D3} " +
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
Console.WriteLine($"Total tasks: {cliRunner.TaskPool.Count}");
foreach (Task<JsonDataFromPoseidon> task in cliRunner.TaskPool)
foreach (CliTaskInfo taskInfo in cliRunner.TaskPool)
{
if (task != null)
Assert.IsNotNull(taskInfo);
Assert.IsNotNull(taskInfo.Task);
if (taskInfo.UseResult)
{
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
Assert.IsNotNull(task, "Expected Task<JsonDataFromPoseidon>.");
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
Console.WriteLine($"Result: {jsonDataFromPoseidon.DeviceId}");
Console.WriteLine($"Result: {jsonDataFromPoseidon?.DeviceId}");
Assert.IsNotNull(jsonDataFromPoseidon);
}
else
{
Assert.Fail($"Task did not complete successfully. State={taskInfo.State}, Status={taskInfo.Task.Status}");
}
}
// Check that the total time is greater than the sum of the individual times
Assert.IsTrue((cliRunner.TaskPool.Count*OneEndTime.Ticks) > delta.Ticks);
Assert.IsTrue((cliRunner.TaskPool.Count * oneEndTime.Ticks) > delta.Ticks);
}
[TestMethod]
public async Task RunMultipleTimesTestProgram_CheckParalelWorkCumulative()
{
SerialPortData serialPort = new SerialPortData("COM3","cmdSleepTest.exe",74);
// Check if the executable exists in current directory
SerialPortData serialPort = new SerialPortData("COM3", "cmdSleepTest.exe", 74);
if (!System.IO.File.Exists(serialPort.SerialPortCmdClientPath))
{
Assert.Inconclusive($"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
Assert.Inconclusive(
$"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
return;
}
List<CliRunner> cliRunnerList = new List<CliRunner>();
for (int i = 0; i < 20; i++)
{
cliRunnerList.Add(new CliRunner(false));
}
CliRunner cliRunnerOne = new CliRunner(false);
DateTime StartTime = DateTime.Now;
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
DateTime startTime = DateTime.Now;
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
serialPort,
SerialPortData.EMeterArg.AllParams);
cliRunnerOne.WaitAll();
TimeSpan OneEndTime = DateTime.Now - StartTime;
StartTime = DateTime.Now;
Console.WriteLine($"Start Time Loop: {StartTime.ToString("yyyy-MM-dd HH:mm:ss")}");
TimeSpan oneEndTime = DateTime.Now - startTime;
startTime = DateTime.Now;
Console.WriteLine($"Start Time Loop: {startTime:yyyy-MM-dd HH:mm:ss}");
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
{
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
serialPort,
SerialPortData.EMeterArg.AllParams);
for (int i = 0; i < 20; i++)
{
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
serialPort,
SerialPortData.EMeterArg.AllParams);
}
}
// Wait for ALL tasks from ALL runners
var allTasks = cliRunnerList.SelectMany(r => r.TaskPool).ToArray();
Task[] allTasks = cliRunnerList
.SelectMany(r => r.TaskPool)
.Where(ti => ti != null && ti.Task != null)
.Select(ti => ti.Task)
.ToArray();
await Task.WhenAll(allTasks);
DateTime EndTime = DateTime.Now;
Console.WriteLine($"End Time Loop: {EndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
TimeSpan delta = EndTime - StartTime;
Console.WriteLine($"Delta Time One process {OneEndTime.Hours:D2}:{OneEndTime.Minutes:D2}:{OneEndTime.Seconds:D2}.{OneEndTime.Milliseconds:D3} " +
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
DateTime endTime = DateTime.Now;
Console.WriteLine($"End Time Loop: {endTime:yyyy-MM-dd HH:mm:ss}");
TimeSpan delta = endTime - startTime;
Console.WriteLine(
$"Delta Time One process {oneEndTime.Hours:D2}:{oneEndTime.Minutes:D2}:{oneEndTime.Seconds:D2}.{oneEndTime.Milliseconds:D3} " +
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
Console.WriteLine($"Total tasks: {cliRunnerList.Sum(runner => runner.TaskPool.Count)}");
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
{
string results = $"iCliRunner: {iCliRunner}";
foreach (Task<JsonDataFromPoseidon> task in cliRunnerList[iCliRunner].TaskPool)
foreach (CliTaskInfo taskInfo in cliRunnerList[iCliRunner].TaskPool)
{
if (task != null)
Assert.IsNotNull(taskInfo);
Assert.IsNotNull(taskInfo.Task);
if (taskInfo.UseResult)
{
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
Assert.IsNotNull(task, "Expected Task<JsonDataFromPoseidon>.");
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
results += ($" ID: {jsonDataFromPoseidon.DeviceId}");
results += $" ID: {jsonDataFromPoseidon?.DeviceId}";
Assert.IsNotNull(jsonDataFromPoseidon);
}
else
{
Assert.Fail(
$"Task did not complete successfully. Runner={iCliRunner}, State={taskInfo.State}, Status={taskInfo.Task.Status}");
}
}
Console.WriteLine(results);
}
// Check that the total time is greater than the sum of the individual times
Assert.IsTrue((cliRunnerList.Count*OneEndTime.Ticks) > delta.Ticks);
Assert.IsTrue((cliRunnerList.Count * oneEndTime.Ticks) > delta.Ticks);
}
}
}
@@ -0,0 +1,249 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
{
[TestClass]
[TestSubject(typeof(CliRunner))]
public class CliRunnerTimeoutTest
{
private static string GetCmdSleepTestPath()
{
var serialPort = new SerialPortData("COM3", "cmdSleepTest.exe", 74);
return serialPort.SerialPortCmdClientPath;
}
private static void EnsureExeExists(string exePath)
{
if (!File.Exists(exePath))
{
Assert.Inconclusive(
$"Test executable '{exePath}' not found. " +
"Please ensure cmdSleepTest.exe exists in the test directory.");
}
}
[TestMethod]
public async Task Timeout_ShouldBeDetected_ForLongRunningTask()
{
string exePath = GetCmdSleepTestPath();
EnsureExeExists(exePath);
var cliRunner = new CliRunner(false);
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
await Task.Delay(200);
bool timedOut = cliRunner.TimeOutReceived(100);
Assert.IsTrue(timedOut, "Timeout should have been detected.");
}
[TestMethod]
public async Task CancelUndoneTasksAsTimedOut_ShouldMarkRunningTaskAsTimedOut()
{
string exePath = GetCmdSleepTestPath();
EnsureExeExists(exePath);
var cliRunner = new CliRunner(false);
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
await Task.Delay(150);
cliRunner.CancelUndoneTasksAsTimedOut();
cliRunner.RefreshTaskStates();
Assert.AreEqual(1, cliRunner.TaskPool.Count);
var taskInfo = cliRunner.TaskPool.Single();
Assert.IsNotNull(taskInfo);
Assert.AreEqual(CliTaskState.TimedOut, taskInfo.State);
Assert.IsFalse(taskInfo.UseResult, "Timed out task must not be used.");
}
[TestMethod]
public void CancelUndoneTasksAsTimedOut_ShouldKeepCompletedTaskCompleted()
{
string exePath = GetCmdSleepTestPath();
EnsureExeExists(exePath);
var cliRunner = new CliRunner(false);
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=50");
try
{
cliRunner.WaitAll();
}
catch
{
// let assertions inspect states
}
cliRunner.RefreshTaskStates();
cliRunner.CancelUndoneTasksAsTimedOut();
cliRunner.RefreshTaskStates();
Assert.AreEqual(1, cliRunner.TaskPool.Count);
var taskInfo = cliRunner.TaskPool.Single();
Assert.IsNotNull(taskInfo);
Assert.AreEqual(CliTaskState.Completed, taskInfo.State);
Assert.IsTrue(taskInfo.UseResult, "Completed task should remain usable.");
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
Assert.IsNotNull(task);
Assert.AreEqual(TaskStatus.RanToCompletion, task.Status);
Assert.IsNotNull(task.Result);
Assert.IsFalse(string.IsNullOrEmpty(task.Result.DeviceId));
}
[TestMethod]
public async Task CancelUndoneTasksAsTimedOut_ShouldKeepDoneTask_AndMarkUndoneTask()
{
string exePath = GetCmdSleepTestPath();
EnsureExeExists(exePath);
var cliRunner = new CliRunner(false);
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=50");
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
await Task.Delay(250);
cliRunner.RefreshTaskStates();
Assert.AreEqual(2, cliRunner.TaskPool.Count);
Assert.AreEqual(1, cliRunner.TaskPool.Count(t => t.State == CliTaskState.Completed),
"Exactly one fast task should be completed before timeout handling.");
cliRunner.CancelUndoneTasksAsTimedOut();
cliRunner.RefreshTaskStates();
var doneTask = cliRunner.TaskPool.Single(t => t.State == CliTaskState.Completed);
var timedOutTask = cliRunner.TaskPool.Single(t => t.State == CliTaskState.TimedOut);
Assert.IsTrue(doneTask.UseResult);
Assert.IsFalse(timedOutTask.UseResult);
var completed = doneTask.Task as Task<JsonDataFromPoseidon>;
Assert.IsNotNull(completed);
Assert.AreEqual(TaskStatus.RanToCompletion, completed.Status);
Assert.IsNotNull(completed.Result);
}
[TestMethod]
public async Task AreTasksDone_ShouldReturnTrue_AfterTimeoutCancellation()
{
string exePath = GetCmdSleepTestPath();
EnsureExeExists(exePath);
var cliRunner = new CliRunner(false);
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
await Task.Delay(150);
Assert.IsFalse(cliRunner.AreTasksDone(), "Task should still be running before timeout cancellation.");
cliRunner.CancelUndoneTasksAsTimedOut();
cliRunner.RefreshTaskStates();
Assert.IsTrue(cliRunner.AreTasksDone(),
"After timed out tasks are marked, runner should report no running tasks.");
}
[TestMethod]
public async Task TimedOutTask_ShouldNotHaveUseResult()
{
string exePath = GetCmdSleepTestPath();
EnsureExeExists(exePath);
var cliRunner = new CliRunner(false);
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
await Task.Delay(150);
cliRunner.CancelUndoneTasksAsTimedOut();
cliRunner.RefreshTaskStates();
var taskInfo = cliRunner.TaskPool.Single();
Assert.AreEqual(CliTaskState.TimedOut, taskInfo.State);
Assert.IsFalse(taskInfo.UseResult);
}
[TestMethod]
public async Task MultipleSlowTasks_ShouldAllBeMarkedTimedOut()
{
string exePath = GetCmdSleepTestPath();
EnsureExeExists(exePath);
var cliRunner = new CliRunner(false);
for (int i = 0; i < 5; i++)
{
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
}
await Task.Delay(200);
cliRunner.CancelUndoneTasksAsTimedOut();
cliRunner.RefreshTaskStates();
Assert.AreEqual(5, cliRunner.TaskPool.Count);
Assert.AreEqual(5, cliRunner.TaskPool.Count(t => t.State == CliTaskState.TimedOut));
Assert.AreEqual(0, cliRunner.TaskPool.Count(t => t.UseResult));
}
[TestMethod]
public void FastTask_WithInvalidJson_ShouldFinishButNotProduceUsefulResult()
{
string exePath = GetCmdSleepTestPath();
EnsureExeExists(exePath);
var cliRunner = new CliRunner(false);
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=50 invalidjson=true");
try
{
cliRunner.WaitAll();
}
catch
{
}
cliRunner.RefreshTaskStates();
Assert.AreEqual(1, cliRunner.TaskPool.Count);
var taskInfo = cliRunner.TaskPool.Single();
Assert.AreEqual(CliTaskState.Completed, taskInfo.State);
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
Assert.IsNotNull(task);
Assert.AreEqual(TaskStatus.RanToCompletion, task.Status);
// depending on your TryJsonStringDeserialize fallback,
// result may be null or an empty/default object
// so avoid asserting UseResult=false here
// instead assert no valid device id
if (task.Result != null)
{
Assert.IsTrue(string.IsNullOrEmpty(task.Result.DeviceId),
"Invalid JSON should not produce a valid DeviceId.");
}
}
}
}
@@ -0,0 +1,76 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
{
[TestClass]
[TestSubject(typeof(CliRunner))]
public class CliRunnerTimeoutUnitTest
{
[TestMethod]
public async Task CancelUndoneTasksAsTimedOut_ShouldMarkOnlyRunningTasks()
{
var cliRunner = new CliRunner(false);
var completedTask = Task.FromResult("done");
var cts = new CancellationTokenSource();
var runningTask = Task.Delay(TimeSpan.FromSeconds(30), cts.Token);
cliRunner.AddTaskForTest(completedTask, "completed");
cliRunner.AddTaskForTest(runningTask, "running", cts);
await Task.Delay(50);
cliRunner.RefreshTaskStates();
cliRunner.CancelUndoneTasksAsTimedOut();
cliRunner.RefreshTaskStates();
Assert.AreEqual(2, cliRunner.TaskPool.Count);
var completed = cliRunner.TaskPool.First(t => t.Name == "completed");
var timedOut = cliRunner.TaskPool.First(t => t.Name == "running");
Assert.AreEqual(CliTaskState.Completed, completed.State);
Assert.IsTrue(completed.UseResult);
Assert.AreEqual(CliTaskState.TimedOut, timedOut.State);
Assert.IsFalse(timedOut.UseResult);
}
[TestMethod]
public void TimeOutReceived_ShouldReturnTrue_WhenElapsedExceedsTimeout()
{
var cliRunner = new CliRunner(false);
Thread.Sleep(30);
Assert.IsTrue(cliRunner.TimeOutReceived(1));
}
[TestMethod]
public async Task AreTasksDone_ShouldReturnTrue_WhenTimedOutTasksAreMarked()
{
var cliRunner = new CliRunner(false);
var cts = new CancellationTokenSource();
var runningTask = Task.Delay(TimeSpan.FromSeconds(30), cts.Token);
cliRunner.AddTaskForTest(runningTask, "running", cts);
await Task.Delay(50);
Assert.IsFalse(cliRunner.AreTasksDone());
cliRunner.CancelUndoneTasksAsTimedOut();
cliRunner.RefreshTaskStates();
Assert.IsTrue(cliRunner.AreTasksDone());
}
}
}
+2
View File
@@ -125,6 +125,8 @@
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\wiredProtocol\TouchReadBaudRateDetectionTests.cs" />
<Compile Include="Rig\RegisterReaders\iPerlASICReader\communication\C4\wiredProtocol\TouchReadFrameBuilderTest.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTest.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTimeoutTest.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTimeoutUnitTest.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReaderTest.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonReader\UniHeadTestCtrlTest.cs" />
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOpTest.cs" />