Compare commits

...
Author SHA1 Message Date
michal a5936c8f19 Fix standing start Store Data
Refactor to use `ICommonRegReader` in `StandingStartSeq` and update parameter handling in `SmartCommunicationSeq`.
2025-12-06 12:48:42 +01:00
michal 2842425673 Add simulation logic for test operations and water metrology, enhance UI initialization, and implement optohead flow rate handling.
- Introduced simulation timers in `FlyingStartStopTestOp`.
- Added `Simulate` methods in `WaterMetrologyData`, `WaterMetrologyDataC7`, and `WaterMetrologyDataC2`.
- Enhanced `SmartCommunicationForm` with textbox resizing logic and initialization code.
- Implemented flow rate and volume calculation from optohead telemetry in `SmartReader`.
- Added unit tests for Poseidon correction parsing.
2025-12-06 12:46:12 +01:00
michal 06a401a1ff bugFix - Morrisville - SerialNr, WMBegginValue
Add support for `ICommonRegReader` interface, enhance `ISmartReader` functionality, and update water meter state handling logic across multiple classes.
2025-11-21 14:14:23 +01:00
michal 3a2fc50fec PurchaseOrderDialog logger Improvement - WRCSwindon
Add detailed logging for purchase order workflows in `CycleBeginningForm`

- Introduced `log_selected` for enhanced debugging of selected orders, items, and serial numbers.
- Added exception handling and logging for serial number loading.
- Improved visibility into runtime behavior with contextual debug and error logs.
2025-11-21 14:12:12 +01:00
michal 38a58ed8b7 Scale rainnig solution, see:
Inplementing mass collection update.
Update AssemblyVersion to 3.9.2149.4, refactor mass collection sequence in StandingStartMassCollection, extend PoseidonCmd with enhanced configuration and dialog options, and improve task handling and UI automation.
2025-11-19 16:44:21 +01:00
michal c7cba20de0 Add ReadStableMassOp unit test and enhance MettlerToledo Scale support
- Introduced `ReadStableMassOpTest` to validate mass reading operations.
- Refactored `Scale` to support `ISerialPort` for improved testability.
- Added `SerialPortDevice` and `SerialPortDeviceFake` implementations, with `GetComponent` overload in `Factory`.
- Enhanced `StateMachine` with `InitializeBoardEtc_Fake` for custom setups.
- Updated project files to include new classes.
2025-11-19 16:28:23 +01:00
michal 6311df49c3 Inplementing mass collection update.
Update AssemblyVersion to 3.9.2149.4, refactor mass collection sequence in StandingStartMassCollection, extend PoseidonCmd with enhanced configuration and dialog options, and improve task handling and UI automation.
2025-11-18 10:59:21 +01:00
michal f1d32a39ba ver 3.9.2149.2 ReadPulses added in Run()
Update AssemblyVersion to 3.9.2149.2 and enhance PoseidonReader with new timing and task-tracking functionality.
2025-11-13 15:58:09 +01:00
michal 224b53f774 Ver 3.9.2149.1 - Update AssemblyVersion and AssemblyFileVersion 2025-11-13 14:39:07 +01:00
michal 1e2777c5e7 Enable ShowDialog for PoseidonCmd, add UI improvements in TestStartEndForm, and introduce new methods for handling reader data and controls. 2025-11-13 14:21:23 +01:00
michal c3c21649fb new Test method Poseidon => StandingStartMassCollectionPoseidon
Add support for `StandingStartMassCollectionPoseidon` test methods.

- Introduced `Compound`, `HeatMeters`, and `Single` components for `StandingStartMassCollectionPoseidon`.
- Included factories, configuration classes, and test parameters for new test methods.
- Updated `TBF.csproj` to include new files and resources.
2025-11-12 13:42:19 +01:00
57 changed files with 4625 additions and 807 deletions
+2 -2
View File
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("3.9.2149.0")]
[assembly: AssemblyFileVersion("3.9.2149.0")]
[assembly: AssemblyVersion("3.9.2149.4")]
[assembly: AssemblyFileVersion("3.9.2149.4")]
@@ -2,6 +2,7 @@
/// Copyright (c) 2021-2023 Sensus Slovensko a.s.
///
using System;
using Common;
using log4net;
using TBF.Rig.Sequences;
@@ -11,6 +12,10 @@ namespace TBF.Rig.ControlBoard.Uni
{
private static readonly ILog log = LogManager.GetLogger(typeof(FlyingStartStopTestOp));
public override string ToString() { return string.Format("FlyingStartStopTestOp()"); }
private DateTime startTimeForSimulation;
private bool simulationTimerStarted = false;
/// Arguments of the constructor
readonly UniCB uniCB;
@@ -123,6 +128,28 @@ namespace TBF.Rig.ControlBoard.Uni
{
log.DebugFormat("Op.Run() opState={0}", opState);
//Simulation of processing time 25 seconds
if (uniCB.DebugLevel == DebugMode.Simulate)
{
if (opState == OpState.StartingTest)
{
startTimeForSimulation = DateTime.Now;
simulationTimerStarted = false;
}
if (opState == OpState.TestInProgress)
{
if (!simulationTimerStarted)
{
startTimeForSimulation = DateTime.Now;
simulationTimerStarted = true;
}
else if (DateTime.Now - startTimeForSimulation > TimeSpan.FromSeconds(25))
{
return Event.TestCompleted;
}
}
}
switch (opState)
{
case OpState.StartingTest:
@@ -8,10 +8,9 @@ using System.Windows.Forms;
using log4net;
using Common;
using TBF.Rig.Sequences;
using TBF.Rig.Output.DB.SensusOracle;
using TBF.Resources;
using System.Drawing;
using NHibernate;
using System.Threading.Tasks;
namespace TBF.Rig.DataEntry.PoseidonCmd
{
@@ -220,6 +219,25 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
orderComboBox.Text = orderComboBox.Items[0].ToString();
}
}
public void AutoClickOkAfterDelay(int delayMs = 10000)
{
_ = AutoClickInternal(okButton, delayMs);
}
private async Task AutoClickInternal(Button clickButton, int delayMs)
{
await Task.Delay(delayMs);
if (clickButton.IsHandleCreated && clickButton.Enabled && clickButton.Visible)
{
// Invoke on UI thread
if (clickButton.InvokeRequired)
clickButton.BeginInvoke(new Action(() => clickButton.PerformClick()));
else
clickButton.PerformClick();
}
}
private void okButton_Click(object sender, EventArgs e)
{
+115 -32
View File
@@ -61,6 +61,15 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
CurrentOp currentOp;
public enum ReadDataOp
{
None,
Start,
Busy,
Done,
}
ReadDataOp readDataOp;
public EntryForm() { }
@@ -112,6 +121,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|| currentOp == CurrentOp.SendStartDataStream)
) throw new Exception("Sequence error");
currentOp = CurrentOp.ReadDatastream_StartStates;
readDataOp = ReadDataOp.None;
//TODO BUMI apply show data in dialog if config required
//entryFormCfg.Direction = Direction.S640;
//currentOp = CurrentOp.EnterTestStartStates;
@@ -122,10 +132,10 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
if (reader != null && reader is PoseidonReader)
{
PoseidonReader poseidonReader = (reader as PoseidonReader);
if (!string.IsNullOrEmpty(poseidonReader.SerialNr)
&& waterMeters.Count > iterator)
if (waterMeters.Count > iterator)
{
waterMeters[iterator].SerialNr = poseidonReader.SerialNr;
if(!string.IsNullOrEmpty(poseidonReader.SerialNr))
waterMeters[iterator].SerialNr = poseidonReader.SerialNr;
}
}
@@ -135,8 +145,17 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
}
/// <returns>null (not implemented)</returns>
public IOperation ShowAdvancedTestStartFormOp(IRegReader[] regReaders, IList<Results.Entities.WaterMeter> waterMeters, bool isCondOp) { return null; }
public IOperation ShowTestCollectFormOp(IRegReader[] regReaders, double volumeRef, double errLimLo, double errLimHi) { return null; }
public IOperation ShowAdvancedTestStartFormOp(IRegReader[] regReaders,
IList<Results.Entities.WaterMeter> waterMeters, bool isCondOp)
{
return null;
}
public IOperation ShowTestCollectFormOp(IRegReader[] regReaders, double volumeRef, double errLimLo,
double errLimHi)
{
return null;
}
/// <returns>Reference to the operation</returns>
public IOperation ShowTestEndFormOp(IRegReader[] regReaders, double refVolume, double errLimLo, double errLimHi)
@@ -155,16 +174,17 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
///
void OpenBeginningDlg(EntryForm myRef)
{
if (!ShowForm)
if (ShowForm == 0)
return;
myRef.modelessDlg = new CycleBeginningForm(TBF.Data.WMsCount, myRef.entryFormCfg,
ProcessData.SelectedProcedure.OrderInfo != null ? ProcessData.SelectedProcedure.OrderInfo.POName : string.Empty);
(myRef.modelessDlg as CycleBeginningForm)?.AutoClickOkAfterDelay();
modelessDlg.Show();
}
///
void OpenTestStartStatesDlg(EntryForm myRef)
{
if (!ShowForm)
if (ShowForm == 0)
return;
myRef.modelessDlg = new TestStartEndForm(myRef.waterMeters.Count, myRef.regReaders, disabled);
modelessDlg.Show();
@@ -172,7 +192,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
///
void OpenTestEndStatesDlg(EntryForm myRef)
{
if (!ShowForm)
if (ShowForm == 0)
return;
myRef.modelessDlg = new TestStartEndForm(TBF.Data.WMsCount, myRef.regReaders, wmStartStateStr, disabled, refVolume, errLimLo, errLimHi);
modelessDlg.Show();
@@ -181,15 +201,19 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
/// <summary>Start this operation</summary>
public void Start()
{
if (!ShowForm)
readDataOp = ReadDataOp.None;
readAndSetDataToMeters = false;
filedDataToMeters = false;
if (ShowForm == 0)
return ;
resultSaved = false;
switch (currentOp)
{
case CurrentOp.SendStartDataStream:
ReadAndSetDataToMeters();
if (ProcessData.SelectedProcedure.OrderInfo == null || entryFormCfg.Direction != Direction.S640)
//ReadAndSetDataToMeters();
if (ProcessData.SelectedProcedure.OrderInfo == null)
{
Program.MainWnd.Invoke(new EntryFormDlgt(OpenBeginningDlg), this);
}
@@ -209,28 +233,81 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
}
}
private bool readAndSetDataToMeters = false;
private bool filedDataToMeters = false;
/// <summary>Run this operation</summary>
/// <returns>Event.ResultsPrinted</returns>
public Event Run()
{
ReadAndSetDataToMeters();
if (!readAndSetDataToMeters) // run until not finished
readAndSetDataToMeters = ReadAndSetDataToMeters();
if (!ShowForm)
return Event.ModelessFormClosed;
if (ProcessData.SelectedProcedure.OrderInfo != null && entryFormCfg.Direction == Direction.S640)
{
for (int i = 0; i < waterMeters.Count; i++)
{
if (waterMeters[i] != null)
waterMeters[i].PurchaseOrder = ProcessData.SelectedProcedure.OrderInfo.POName;
}
return Event.ModelessFormClosed;
}
if (ShowForm == 0)
if(readAndSetDataToMeters)
return Event.ModelessFormClosed;
else
{
return Event.ModelessFormIsOpen;
}
if ((modelessDlg is IHasCompleted) && !(modelessDlg as IHasCompleted).Completed)
if (readAndSetDataToMeters && !filedDataToMeters)
{
return Event.ModelessFormIsOpen;
if (regReaders != null)
{
//add data into dialog
int item = 0;
TestStartEndForm dlg = (modelessDlg as TestStartEndForm);
foreach (var iRegReader in regReaders)
{
if (iRegReader is PoseidonReader poseidonReader)
{
if (dlg != null)
{
if (currentOp == CurrentOp.ReadDatastream_StartStates)
{
dlg.WMStartState[item] = poseidonReader.BeginWMState;
dlg.WMStartStateStr[item] = poseidonReader.BeginWMState.ToString();
}
if (currentOp == CurrentOp.ReadDatastream_EndStates)
dlg.WMEndState[item] = poseidonReader.EndWMState;
}
}
item++;
}
if (dlg != null)
{
if (dlg.InvokeRequired)
{
dlg.BeginInvoke(new Action(() =>
{
dlg.UpdateValues(currentOp == CurrentOp.ReadDatastream_StartStates, true);
if (entryFormCfg.ShowDialogType == ShowDialogType.ContinueAutomatically)
{
dlg.AutoClickOkAfterDelay();
}
}));
}
else
{
dlg.UpdateValues(currentOp == CurrentOp.ReadDatastream_StartStates, true);
if (entryFormCfg.ShowDialogType == ShowDialogType.ContinueAutomatically)
{
dlg.AutoClickOkAfterDelay();
}
}
}
filedDataToMeters = true;
}
}
if ((modelessDlg is IHasCompleted) && !(modelessDlg as IHasCompleted).Completed)
{
return Event.ModelessFormIsOpen; //ModelessFormClosed ??
}
if (!resultSaved) /// This is to save the result only once
@@ -290,11 +367,13 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
modelessDlg = null;
}
currentOp = CurrentOp.None;
readAndSetDataToMeters = false;
filedDataToMeters = false;
}
public bool ShowForm
public int ShowForm
{
get { return entryFormCfg == null ? false : entryFormCfg.ShowDialog; }
get { return entryFormCfg == null ? ShowDialogType.Hide.GetHashCode() : entryFormCfg.ShowDialogType.GetHashCode(); }
set {} // only for read - svia dilalog
}
@@ -303,13 +382,15 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
get { return entryFormCfg == null ? false : entryFormCfg.SaveCommunication;}
}
//private long GetMaxtime()
public bool ReadAndSetDataToMeters()
{
bool bOperationSuccess = false;
if (currentOp == CurrentOp.SendStartDataStream)
{
bool finishedReading = regReaders == null; // we can work only with register readers
while (!finishedReading)
while (!finishedReading) //TODO BUMI lock - fuck ?
{
bool bAllReadersFinished = true;
foreach (var iRegReader in regReaders )
@@ -326,6 +407,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
}
/// Send start data stream
poseidonReader.Run();
readDataOp = ReadDataOp.Start;
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error))
{
@@ -337,10 +419,11 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
if (bAllReadersFinished)
{
finishedReading = true;
readDataOp = ReadDataOp.Done;
}
else
{
System.Threading.Thread.Sleep(100);
System.Threading.Thread.Sleep(10);
}
}
@@ -350,7 +433,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|| (currentOp == CurrentOp.ReadDatastream_EndStates))
{
bool finishedReading = regReaders == null; // we can work only with register readers
while (!finishedReading)
while (!finishedReading) //TODO BUMI lock - fuck ?
{
bool bAllReadersFinished = true;
foreach (var iRegReader in regReaders )
@@ -383,7 +466,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
}
else
{
System.Threading.Thread.Sleep(100);
System.Threading.Thread.Sleep(10);
}
}
+44 -11
View File
@@ -3,6 +3,7 @@
///
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using Common;
using Config.Entities;
@@ -52,6 +53,15 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
#endif
Count,
}
public enum ShowDialogType
{
[Description("Do not Show")] Hide,
[Description("Continue Automatically")] ContinueAutomatically,
[Description("Continue Manually")] ContinueManually,
Count,
}
public class EntryFormCfg : ComponentCfgBase, IComponentCfg, IParamsProvider
{
@@ -69,6 +79,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
public Direction Direction;
public Orders Orders;
public bool ShowDialog;
public ShowDialogType ShowDialogType;
public bool SaveCommunication;
/// Private parameterless constructor invoked by all other (public) constructors
@@ -89,7 +100,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
{
Direction = Direction.Forward_RL;
Orders = Orders.Arbitrary;
ShowDialog = false;
ShowDialogType = ShowDialogType.Hide;
SaveCommunication = false;
}
@@ -115,8 +126,9 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
for (Orders o = 0; o < Orders.Count; o++) list.Add(o.ToDescription());
return list;
case 2:
list.Add("True");
list.Add("False");
list.Add(ShowDialogType.Hide.ToDescription());
list.Add(ShowDialogType.ContinueAutomatically.ToDescription());
list.Add(ShowDialogType.ContinueManually.ToDescription());
return list;
case 3:
list.Add("True");
@@ -126,6 +138,19 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
return null;
}
}
public static bool TryFromInt<TEnum>(int value, out TEnum result)
where TEnum : struct, Enum
{
if (Enum.IsDefined(typeof(TEnum), value))
{
result = (TEnum)(object)value;
return true;
}
result = default;
return false;
}
public string ToString(int i)
@@ -134,10 +159,10 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
{
case 0: return Direction.ToDescription();
case 1: return Orders.ToDescription();
case 2: return ShowDialog.ToString();
case 2: return ShowDialogType.ToDescription();
case 3: return SaveCommunication.ToString();
default:
return string.Format("Name={0}, Direction={1}, Orders={2}, ShowDialog={3}, StoreCommunication={4}", Name, Direction, Orders, ShowDialog, SaveCommunication);
return string.Format("Name={0}, Direction={1}, Orders={2}, ShowDialog={3}, StoreCommunication={4}", Name, Direction, Orders, ShowDialogType, SaveCommunication);
}
}
@@ -164,11 +189,14 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
break;
case 2:
{
bool lastSetting = ShowDialog;
if (str == "True") ShowDialog = true;
else ShowDialog = false;
if (lastSetting != ShowDialog)
return CfgUpdateFlags.RestartRqrd;
ShowDialogType lastSetting = ShowDialogType;
for (ShowDialogType s = 0; s < ShowDialogType.Count; s++)
if (s.ToDescription() == str)
{
ShowDialogType = s;
if (lastSetting != ShowDialogType)
return CfgUpdateFlags.RestartRqrd;
}
}
break;
case 3:
@@ -196,6 +224,11 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
if (ParamValues(i).Contains(str)) return true;
break;
case 2:
bool exists = Enum.GetValues(typeof(ShowDialogType))
.Cast<ShowDialogType>()
.Any(d => d.ToDescription() == str);
if (exists) return true;
break;
case 3:
if (str == "True" || str == "False") return true;
break;
@@ -212,7 +245,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
{
prms.Direction = this.Direction;
prms.Orders = this.Orders;
prms.ShowDialog = this.ShowDialog;
prms.ShowDialogType = this.ShowDialogType;
prms.SaveCommunication = this.SaveCommunication;
}
@@ -3,6 +3,7 @@
///
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
using log4net;
using TBF.Rig.GenericDevices;
@@ -99,9 +100,12 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
this.disabled = disabled;
ShuffleTextBoxes();
ResizeDlgToFitEnabledControls();
WMStartState = new double[waterMetersCount];
WMStartStateStr = new string[waterMetersCount];
SetUiBusy(true);
}
/// <summary>
@@ -130,8 +134,41 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
this.warningLimHi = 2 * errLimHi;
ShuffleTextBoxes();
ResizeDlgToFitEnabledControls();
WMEndState = new double[waterMetersCount];
SetUiBusy(true);
}
private void SetUiBusy(bool busy, long deltaTime = -1)
{
// show wait cursor for form and children
this.UseWaitCursor = busy;
// block editing textboxes
for (int i = 0; i < enabledTextBoxes.Count; i++)
{
enabledTextBoxes[i].Enabled = !busy;
}
// disable buttons while busy
if (okButton != null) okButton.Enabled = !busy;
// show/hide "loading..." label
if (loadingLabel != null)
{
loadingLabel.Visible = busy;
loadingLabel.Text = "Loading...";
if (deltaTime > 0)
{
//show delta time in label
loadingLabel.Visible = true;
loadingLabel.Text = string.Format("Get: {0} s", deltaTime/1000.0);
}
}
}
/// <summary>
@@ -159,6 +196,43 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
TextBoxesCount = TBF.Data.WMsCount;
}
}
void ResizeDlgToFitEnabledControls()
{
int xMax = 0;
int yMax = 0;
GetMaxDimensions(startTextBoxes,WaterMetersCount,ref xMax, ref yMax);
GetMaxDimensions(endTextBoxes,WaterMetersCount, ref xMax, ref yMax);
int shapeGap = 50;
okButton.Left = xMax + shapeGap;
xMax = okButton.Left + okButton.Width;
Width = xMax + shapeGap;
Height = yMax + shapeGap;
}
private void GetMaxDimensions(TextBox[] textBoxes, int waterMetersCount, ref int xMax, ref int yMax)
{
for (int i = 0; i < waterMetersCount; i++)
{
if (textBoxes[i].Left + textBoxes[i].Width > xMax)
xMax = textBoxes[i].Left + textBoxes[i].Width;
if (textBoxes[i].Top + textBoxes[i].Height > yMax)
yMax = textBoxes[i].Top + textBoxes[i].Height;
}
}
// private void GetMaxDimensions(TextBox[] textBoxes, ref int xMax, ref int yMax)
// {
// for (int i = 0; i < textBoxes.Length; i++)
// {
// if(!textBoxes[i].Visible)
// continue;
// if (textBoxes[i].Left + textBoxes[i].Width > xMax) xMax = textBoxes[i].Left + textBoxes[i].Width;
// if (textBoxes[i].Top + textBoxes[i].Height > yMax) yMax = textBoxes[i].Top + textBoxes[i].Height;
// }
// }
private void CycleEndForm_Load(object sender, EventArgs e)
{
@@ -211,6 +285,43 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
}
}
public void UpdateValues(bool stratValue = true, bool enableEdit = false, long deltaTime = -1)
{
// Ensure we are on the UI thread
if (InvokeRequired)
{
BeginInvoke(new Action(() => UpdateValues(stratValue, enableEdit)));
return;
}
for (int i = 0; i < TextBoxesCount; i++)
{
if (stratValue)
{
if (WMStartStateStr != null && i < WMStartStateStr.Length)
{
startTextBoxes[i].Text = WMStartStateStr[i];
}
}
else
{
// small bugfix: check WMEndState, not WMStartStateStr
if ((WMEndState != null && i < WMEndState.Length) &&
(WMStartStateStr != null && i < WMStartStateStr.Length && WMStartStateStr[i] != ""))
{
endTextBoxes[i].Text = WMEndState[i].ToString();
}
}
}
if (enableEdit)
{
SetUiBusy(false, deltaTime);
}
// if you also need to enable/disable editing, do it here,
// it's now safely on the UI thread.
}
void Localize()
{
Text = Strings.Water_Meter_States;
@@ -258,6 +369,26 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
completed = true;
Close();
}
public void AutoClickOkAfterDelay(int delayMs = 10000)
{
_ = AutoClickInternal(okButton, delayMs);
}
private async Task AutoClickInternal(Button okButton, int delayMs)
{
await Task.Delay(delayMs);
if (okButton.IsHandleCreated && okButton.Enabled && okButton.Visible)
{
// Invoke on UI thread
if (okButton.InvokeRequired)
okButton.BeginInvoke(new Action(() => okButton.PerformClick()));
else
okButton.PerformClick();
}
}
#region Forced close handling
File diff suppressed because it is too large Load Diff
@@ -21,6 +21,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
public partial class CycleBeginningForm : Form, GenericDevices.IHasCompleted
{
private static readonly ILog log = LogManager.GetLogger(typeof(CycleBeginningForm));
private static readonly ILog log_selected = LogManager.GetLogger("PurchaseOrderHistory");
/// <summary> Number of water meters </summary>
public readonly int WaterMetersCount;
@@ -264,6 +265,11 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
Disabled[i] = !checkBoxes[i].Checked;
}
//TODO create logger to log selected items and their order and Order number
string snTextArrString = SNText != null ? string.Join(", ", SNText) : string.Empty;
log_selected.DebugFormat("Purchase DLG - Selected Order: {0}, Last selected Box: {1}, All items: {2}",
orderComboBox.Text, purchaseBoxComboBox.Text,snTextArrString);
completed = true;
Close();
}
@@ -718,6 +724,17 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
.SelectMany(pBox => pBox.PurchaseWaterMeterDataList)
.Select(pWM => pWM.SerialNo);
try
{
string[] iEnumerable = serialNumbers as string[] ?? serialNumbers.ToArray();
log_selected.Debug(
$"Selected order: {choosenOrder} box: {choosenBox} possible serial numbers (form DB): {string.Join(", ", iEnumerable)}");
}
catch (Exception e)
{
log_selected.Error("Error loading serial numbers: " + e);
}
//enable behaviour type
bool addOnEndOnly = false;
@@ -726,6 +743,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
if (countOfFreeBoxes < serialNumbers.Count())
{
log_selected.Debug(">" + serialNumbers.Count() + " Serial Numbers in box as we have free positions!");
MessageBox.Show(this, "We have more Serial Numbers in box as we have free positions!", "Warning",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
@@ -753,6 +771,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
if (lastComboBoxSerialNo >= 0 || lastComboBoxSerialNo < enabledComboBoxes.Count)
{
comboBoxes[lastComboBoxSerialNo].Text = serialNumber;
log_selected.Debug($"Added serial no: {serialNumber} to pos: {lastComboBoxSerialNo}");
lastComboBoxSerialNo++;
}
}
@@ -762,6 +781,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
if (iNextFreeNumber >= 0 || iNextFreeNumber < enabledComboBoxes.Count)
{
comboBoxes[iNextFreeNumber].Text = serialNumber;
log_selected.Debug($"Added serial no: {serialNumber} to pos: {iNextFreeNumber}");
lastComboBoxSerialNo = iNextFreeNumber;
}
}
@@ -774,6 +794,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
if (!noImplementedSerialNumbers.IsEmpty())
{
log_selected.Debug("No implemented serial numbers: " + noImplementedSerialNumbers);
MessageBox.Show(this,
string.Format("The following serial numbers were not implemented: {0}", noImplementedSerialNumbers),
"Serial Numbers repeating!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
@@ -2,7 +2,10 @@ namespace TBF.Rig.GenericDevices
{
public interface IHasFromUNIDisablePossibility
{
bool ShowForm { get; set; }
/// <summary>
/// 0 - disabled, > 1 - enabled but can have variable uses how form is shown
/// </summary>
int ShowForm { get; set; }
bool ReadAndSetDataToMeters();
}
@@ -3,16 +3,42 @@
///
using System;
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols;
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
{
public class OptoReceivedEventArgs : EventArgs
{
public string Data;
public WaterMetrologyData WaterMetrologyData;
public byte[] RawData;
public OptoReceivedEventArgs(string data)
{
this.Data = data;
WaterMetrologyData = null;
RawData = null;
}
public OptoReceivedEventArgs(string data, WaterMetrologyData waterMetrologyData)
{
this.Data = data;
this.WaterMetrologyData = waterMetrologyData;
RawData = null;
}
public OptoReceivedEventArgs(byte[] data)
{
this.RawData = data;
Data = null;
WaterMetrologyData = null;
}
public OptoReceivedEventArgs(WaterMetrologyData data)
{
WaterMetrologyData = data;
Data = null;
RawData = null;
}
}
}
@@ -506,15 +506,9 @@ namespace TBF.Rig.RegisterReaders.IPerlReader.implementations
get { return wmVolume; }
}
public double BeginWMState
{
get { return beginWMState; }
}
public double BeginWMState { get { return beginWMState; } set { beginWMState = value; } }
public double EndWMState
{
get { return endWMState; }
}
public double EndWMState { get { return endWMState; } set { endWMState = value; } }
public IOperation ReadDatastreamOp()
{
@@ -17,6 +17,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
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); }
@@ -39,6 +40,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
get => startTime;
}
public long IncommingTime
{
get => incommingTime;
}
public bool TimeOutReceived(long timeout)
{
return (DateTime.Now.Ticks - startTime) > timeout;
@@ -121,6 +127,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
throw;
}
//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;
@@ -17,18 +17,21 @@ using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
using TBF.Rig.RegisterReaders.SerialStream;
using TBF.Rig.RegisterReaders.StandingStartStop;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
public class PoseidonReader : ComponentBase, IDevice, IRegReaderDatastream, ISessionDataMngmnt, IOperation
public class PoseidonReader : ComponentBase, IDevice, IRegReaderDatastream, ISessionDataMngmnt, IOperation, ICommonRegReader
{
private static readonly ILog log = LogManager.GetLogger(typeof(PoseidonReader));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
readonly PoseidonCfg registerReaderCfg;
readonly ControlBoard.IControlBoard controlBoard;
public int ComPortNr => registerReaderCfg?.ComPortNr ?? -1;
public PoseidonCfg RegPoseidonCfg => registerReaderCfg;
private bool activeHandlerSessioEnabled = false;
private CliRunner _cliRunner;
@@ -134,10 +137,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
public int WMPulses { get { return wmPulses; } }
public int WMRefPulses { get { return wmRefPulses; } }
public double WMVolume { get { return wmVolume; } }
public double BeginWMState { get { return beginWMState; } }
public double EndWMState { get { return endWMState; } }
public double BeginWMState { get { return beginWMState; } set { beginWMState = value;} }
public double EndWMState { get { return endWMState; } set { endWMState = value;} }
public double WMTestTime { get { return wmTestTime; } }
public string SerialNr { get => wmSerialNr; }
public string SerialNr { get => wmSerialNr; set => wmSerialNr = value; }
double beginWMState;
@@ -147,6 +150,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
int wmRefPulses;
double wmTestTime;
private string wmSerialNr;
int timeFromStart; /// [s] Time from test start to determine when the test start sample should be taken
public IOperation ReadDatastreamOp()
@@ -314,7 +319,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
private void ReadPulses()
{
wmRefPulses = controlBoard.RefPulses;
wmRefPulses = controlBoard?.RefPulses ?? 0;
}
@@ -326,13 +331,25 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
/// <summary>
/// for debug purposes what time will consume answer
/// </summary>
private long startTimeInMilis, fullTimeInMilis;
private static long SafetyTimeOut = 30 * 1000; /// 30 seconds
private long startTimeInMilis = -1, fullTimeInMilis = -1;
private static long SafetyTimeOut = 30 * 1000;
private long incommingTime = -1;
/// 30 seconds
public long DeltaTime { get{return fullTimeInMilis;}}
public long IncommingTime { get{return incommingTime;}}
/// <summary>Run this operation</summary>
/// <returns>eventDone</returns>
public Event Run()
{
lock (this)
{
timeFromStart += StateMachine.Period;
ReadPulses();
}
if (_currentOp == CurrentPoseidonOp.SendStartDataStream)
{
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.AllParams);
@@ -349,6 +366,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
}
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Done)
{
var firstTask = CliRunner.TaskPool.FindLast(t => t is Task<string>);
if (firstTask != null && firstTask is Task<string>)
{
string data = null;
data = (firstTask as Task<string>).Result;
if (data != null && TryGetDeviceId(data, out wmSerialNr))
{
}
}
_currentOp = CurrentPoseidonOp.Done;
return Event.Done;
}
@@ -356,6 +387,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
{
startTimeInMilis = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
incommingTime = -1;
_isReadingStart = (_currentOp == CurrentPoseidonOp.ReadDataStream_Start);
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
_currentOp = CurrentPoseidonOp.ReadDatastream_Running;
@@ -366,6 +398,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|| CliRunner.TimeOutReceived(SafetyTimeOut))
{
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
//set time stamp - end of reading
incommingTime = CliRunner.IncommingTime;
}
return Event.Busy;
}
@@ -379,6 +413,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
data = (first as Task<JsonDataFromPoseidon>).Result;
//GET serial number
if (string.IsNullOrEmpty(wmSerialNr))
{
try
{
wmSerialNr = data?.DeviceId ?? wmSerialNr;
}
catch (Exception e)
{
log.Error("Serial Nr - parse error!");
}
}
//GET volume
if (data != null && Double.TryParse(data.Reading, out double Volume))
{
double VolumeLi = Units.ConvertFrom(Unit.USgal, Volume);
@@ -396,6 +444,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
}
}
//Finish reading and loop
_currentOp = CurrentPoseidonOp.Done;
return Event.Done;
}
@@ -457,34 +507,38 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
public void StartSession()
{
ValidateCliFileExistence(false);
if (DebugLevel == DebugMode.Simulate)
{
wmSerialNr = "777321";
}
else
{
//TODO BUMI start session - CMD send data to Poseidon
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId);
CliRunner.WaitAll();
foreach (Task task in CliRunner.TaskPool)
{
if (task is Task<string>)
{
string result = (task as Task<string>).Result;
if (TryGetDeviceId(result, out wmSerialNr))
{
break;
}
}
}
CliRunner.Clear();
}
//this is no place to get device id
}
// private void RetrieveDeviceIdFromResponse()
// {
// if (DebugLevel == DebugMode.Simulate)
// {
// wmSerialNr = "777321";
// }
// else
// {
// //TODO BUMI start session - CMD send data to Poseidon
//
// CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId);
// CliRunner.WaitAll();
// foreach (Task task in CliRunner.TaskPool)
// {
// if (task is Task<string>)
// {
// string result = (task as Task<string>).Result;
// if (TryGetDeviceId(result, out wmSerialNr))
// {
// break;
// }
// }
// }
//
// CliRunner.Clear();
// }
// }
private static readonly Regex DeviceIdRegex = new Regex(
@"(?im)(?:" +
@"^\s*Device\s*Id\s*:\s*([^\r\n]+)\s*$" + // old format
@@ -2,6 +2,7 @@ using System;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Windows.Forms.VisualStyles;
using System.Xml.Linq;
using Common;
using Common.Iperl;
@@ -11,6 +12,8 @@ using NHibernate;
using Sensus.iPerl.NfcHandler;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7;
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using CalibrationStruct = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.CalibrationStruct;
@@ -45,6 +48,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
readonly PoseidonCfg _poseidonCfg;
public PoseidonCfg RegPoseidonCfg { get { return _poseidonCfg; } }
public int RfidComPortNr { get { return _poseidonCfg.RfidComPortNr; } }
public int OptoComPortNr { get { return _poseidonCfg.OptoComPortNr; } }
public MeterType MeterType { get { return _poseidonCfg.MeterType; } }
@@ -86,6 +90,21 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
float[] x;
public float[] X { get { return x; } }
// Volume of water from the opto telegram
private DateTime _firstSampleTime;
private DateTime _lastSampleTime;
private double _averageFlow;
private long _averageFlowCount;
private readonly object _avgLock = new object();
private bool _optoheadStarted = false;
private OptoHeadService _optoHeadService;
/// <summary>
/// Passed to OptoTelegramRaw.UpdateFromString(...)
@@ -164,9 +183,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
///
/// Timestamp from the opto telegram
///
private Int64 lastTimestamp;
private double timestampSec;
private double timestampSec0;
int timeFromStart; /// [s] Time from test start to determine when the test start sample should be taken
@@ -174,12 +191,22 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
/// Test start volume for metrology in seconds
public double TimestampSecStart
{
get { return TimeFromSamples(optoData, optoDataCount, TestStartTelegramIx, StartEndFilterSamplesCount2); }
get
{
return _lastSampleTime != DateTime.MinValue ? 1 : 0; // return one second if is initialized, 0 - is false
//return TimeFromSamples(optoData, optoDataCount, TestStartTelegramIx, StartEndFilterSamplesCount2);
}
}
/// Test end time for metrology in seconds
public double TimestampSecEnd
{
get { return TimeFromSamples(optoData, optoDataCount, TestEndTelegramIx, StartEndFilterSamplesCount2); }
get
{
if (_lastSampleTime == DateTime.MinValue) return 0;
TimeSpan delta = _lastSampleTime - _firstSampleTime;
return (delta.TotalSeconds + 1);
//return TimeFromSamples(optoData, optoDataCount, TestEndTelegramIx, StartEndFilterSamplesCount2);
}
}
///
public bool NoSamples
@@ -197,12 +224,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
/// Test start volume for metrology in liters
public double VolumeLtrStart
{
get { return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestStartTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2); }
get
{
return 0;
//return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestStartTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2);
}
}
/// Test end volume for metrology in liters
public double VolumeLtrEnd
{
get { return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestEndTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2); }
get
{
return wmVolume; // complet calculated volume (time * flowrate)
//return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestEndTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2);
}
}
@@ -274,9 +309,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
{
if (_poseidonCfg != null)
{
OpenOptoSerialPort($"COM{_poseidonCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One,
Handshake.None);
CloseOptoSerialPort();
// OpenOptoSerialPort($"COM{_poseidonCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One,
// Handshake.None);
// CloseOptoSerialPort();
log.FatalFormat($"{Name} initialized: {this}");
}
else
@@ -369,8 +405,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
public int WMPulses { get { return wmPulses; } }
public int WMRefPulses { get { return wmRefPulses; }}
public double WMVolume { get { return wmVolume; } }
public double BeginWMState { get { return beginWMState; } }
public double EndWMState { get { return endWMState; } }
public double BeginWMState { get { return beginWMState;} set => beginWMState = value; }
public double EndWMState { get { return endWMState; } set => endWMState = value; }
public IOperation ReadDatastreamOp()
{
return this;
@@ -401,6 +437,16 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
Q2CorrRL = 0;
Q2CorrLR = 0;
lock (_avgLock)
{
_firstSampleTime = DateTime.MinValue;
_lastSampleTime = DateTime.MinValue;
_averageFlow = 0;
_averageFlowCount = 0;
log.Debug("Initializing datastream state");
}
simulatedPcbNr = null;
dataStreamState = DataStreamState.Flush;
@@ -442,6 +488,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
{
timeFromStart += StateMachine.Period;
ReadPulses();
//TODO read flow
if (_optoHeadService!= null && !_optoHeadService.IsRunning)
StartOptohead();
if (!startSampleAcquired && (timeFromStart >= 8) && (currentTelegramIx >= 0))
{
@@ -462,7 +514,94 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
return Event.ReadRegisterDone;
}
/// <summary>
private void StartOptohead()
{
lock (_avgLock)
{
_firstSampleTime = DateTime.MinValue;
_lastSampleTime = DateTime.MinValue;
_averageFlow = 0;
_averageFlowCount = 0;
}
StartOptoTestInputLoop(new EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs>(OnOptoHandler));
}
private bool OpenOptoConnection(PoseidonCfg iHeadCfg)
{
try
{
if (iHeadCfg != null)
{
if (_optoHeadService != null) return false;
OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}", iHeadCfg.DebugLevel);
_optoHeadService = new OptoHeadService(connection);
return _optoHeadService.CreateSerialConnection();
}
}
catch (Exception ex)
{
throw ex;
}
return false;
}
private bool StartOptoTestInputLoop(EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs> onOptoReceivedHandler)
{
try
{
if (_optoHeadService != null)
{
if (_optoHeadService.IsRunning) return false;
_optoHeadService.RunLoop(onOptoReceivedHandler);
//run loop runstate = true;
return true;
}
}
catch (Exception ex)
{
log.Error(ex.Message);
throw ex;
}
return false;
}
private void OnOptoHandler(object sender, CommonRR.IPerl.communication.OptoReceivedEventArgs e)
{
//received data from optohead
WaterMetrologyData eWaterMetrologyData = e?.WaterMetrologyData;
if (eWaterMetrologyData != null && eWaterMetrologyData.C7Data != null)
{
double flowRateLPerS = eWaterMetrologyData.C7Data?.FlowRateLPerS ?? 0;
lock (_avgLock)
{
if (_averageFlowCount == 0)
{
_firstSampleTime = eWaterMetrologyData.C7Data?.Dt ?? DateTime.Now;
}
_lastSampleTime = eWaterMetrologyData.C7Data?.Dt ?? DateTime.Now;
_averageFlowCount++;
// Running average (no overflow)
_averageFlow += (flowRateLPerS - _averageFlow) / _averageFlowCount;
TimeSpan delta = _lastSampleTime - _firstSampleTime;
if (delta.TotalMilliseconds == 0)
wmVolume = 0;
else
wmVolume = _averageFlow * (delta.TotalMilliseconds / 1000); //volume in liters
//wmVolume = Units.ConvertFrom(Unit.l, _averageFlow * (delta.TotalMilliseconds / 1000));
log.Info("Calculated Value:" + wmVolume);
}
}
}
/// <summary>
/// Stop this operation
/// </summary>
public void Stop()
@@ -570,78 +709,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
}
/// <summary>
/// Q2 correction factor calculated from the last test (Q2).
/// This factor should be used only for R800 meters.
/// </summary>
/// <param name="q2TestResult">A test result from which to calculate the factor</param>
/// <param name="nominalFlow">Nominal flow in m3/h</param>
/// <param name="currentFactor">0 or the current Q2 correction factor when updating the factor</param>
/// <returns>Calculated Q2 correction factor</returns>
public double CalculateQ2CorrectionFactor(Results.Entities.MeterTestRslt currentQ2Result, int currentFactor, double nominalFlow, double errorTarget = 0)
{
double nominalTestFlowLph = Units.ConvertTo(Unit.lph, nominalFlow);
double volumeRefShiftedToTarget = currentQ2Result.VolumeRef * (1.0 + errorTarget / 100.0);
double q2adjErrorShiftedToTarget = Config.Formulas.ErrorFromVolumes(currentQ2Result.VolumeMeter, volumeRefShiftedToTarget);
double A = 16.0 / ScalingFactor(); /// Raw units per ml: DN15=16, DN20=8, DN25=4, DN32=2, DN40=1
const double B = 8.0; /// Raw units per minute, 8
const double C = B * 60.0; /// Raw units per hour, 480
double D = C / A; /// ml correction per hour
double F = D / (nominalTestFlowLph * 10.0); /// Error corrected with 8 Raw Units per minute [%]
double G = F / B; /// Error corrected with 1 Raw Unit per minute [%]
/// Do not change the factor for an invalid measurement (q2adjResult.VolumeMeter == 0)
double q2CorrectionFactor = (Math.Abs(currentQ2Result.VolumeMeter) <= float.Epsilon) ? Convert.ToDouble(currentFactor) :
Convert.ToDouble(currentFactor) - (q2adjErrorShiftedToTarget / G) * (volumeRefShiftedToTarget / currentQ2Result.VolumeMeter);
log.WarnFormat("CalculateQ2CorrectionFactor() : Pos={0}, PCB#={1}, Error={2}%, Target={3}%, Current factor={4} New factor={5}",
Name,
SerialNr,
currentQ2Result.Error.ToString("F2"),
errorTarget.ToString("F3"),
currentFactor.ToString("F1"),
q2CorrectionFactor.ToString("F1"));
return q2CorrectionFactor;
}
/// <summary>
/// 2 Hz correction factor calculated from two Q3 tests - done at 2Hz and at 8Hz.
/// This factors should be used only for DN32 and DN40 meters.
/// </summary>
/// <param name="resultAt2Hz">Test result @2Hz from which to calculate the factor</param>
/// <param name="resultAt8Hz">Test result @8Hz from which to calculate the factor</param>
/// <param name="hz2CorrectionFactor">The calculated Q2 correction factor</param>
/// <returns>true = OK, false = failed</returns>
public bool Calculate2HzCorrectionFactor(Results.Entities.MeterTestRslt resultAt2Hz,
Results.Entities.MeterTestRslt resultAt8Hz,
out double diff2Hz8Hz, out int hz2CorrectionFactor)
{
hz2CorrectionFactor = 0;
diff2Hz8Hz = 0;
if ((resultAt2Hz == null) || (resultAt8Hz == null))
{
return false; /// Test result @2Hz and/or @8Hz is missing ==> water meter failed
}
diff2Hz8Hz = resultAt2Hz.Error - resultAt8Hz.Error;
if (Math.Abs(diff2Hz8Hz) > 2.5) return false; /// Difference of errors > 2.5 % ==> water meter failed
hz2CorrectionFactor = -1 * (int)Math.Round(10 * diff2Hz8Hz);
log.WarnFormat("2Hz correction: Pos={0}, PCB#={1}, corrFactor={2}, erro@2Hz={3}%, erro@8Hz={4}%",
Name,
SerialNr,
hz2CorrectionFactor,
resultAt2Hz.Error.ToString("F2"),
resultAt8Hz.Error.ToString("F2"));
return true;
}
/// <summary>
@@ -703,147 +771,24 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
/// <param name="optoState">OptoState.Read or OptoState.Flush</param>
void ReadOptoData(DataStreamState optoState)
{
if (optoSerialPort is null) return;
lock (this)
{
int nrBytes = optoSerialPort.BytesToRead;
if (nrBytes > 0)
{
char[] buffer = new char[nrBytes];
optoSerialPort.Read(buffer, 0, nrBytes);
string received = new string(buffer);
string allRcvd = partOfTelegram + received;
while (true)
{
int pos = allRcvd.IndexOf("\r\n");
if (pos < 0)
{
/// No CR+LF found, wait for more characters in the next invocation
partOfTelegram = allRcvd;
return;
}
else
{
/// CR+LF found
if (optoState == DataStreamState.ProcessAndSave)
{
int bufferIx = BufferIdx(optoDataCount);
if (pos < OptoTelegramRaw.Length - 2)
{
/// CR+LF found too early, truncate the beginning incl CR+LF and keep scanning in this loop
allRcvd = allRcvd.Substring(pos + 2);
if (synchronized)
{
optoData[bufferIx].Counter = optoDataCount;
optoData[bufferIx].SetFlags(OptoTelegramFlags.SyncError);
}
synchronized = true;
}
else if (optoData[bufferIx].UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2),
optoDataCount,
Convert.ToSingle(Sequences.ProcessData.RefFlow.Val),
ref volumeRawExtLast, ref timestampExtLast))
{
/// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) && the telegram is OK
flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast);
OptoTelegramReceived(optoDataCount, synchronized2, volumeRawExtLast, timestampExtLast);
synchronized2 = synchronized;
allRcvd = allRcvd.Substring(pos + 2);
}
else
{
/// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) but the telgram was not OK
optoData[bufferIx].Counter = optoDataCount;
optoDataCount++;
allRcvd = allRcvd.Substring(pos + 2);
}
optoDataCount++;
}
else /// optoState == OptoState.Flush
{
if (pos < OptoTelegramRaw.Length - 2)
{
/// CR+LF found too early, truncate the beginning incl CR+LF and keep scanning in this loop
allRcvd = allRcvd.Substring(pos + 2);
synchronized = true;
}
// CR+LF found and (pos >= OptoTelegram.Length - 2)
else if (toBeFlushed.UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2),
0,
Convert.ToSingle(Sequences.ProcessData.RefFlow.Val),
ref volumeRawExtLast, ref timestampExtLast))
{
flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast);
synchronized2 = synchronized;
allRcvd = allRcvd.Substring(pos + 2);
}
else
{
allRcvd = allRcvd.Substring(pos + 2);
}
}
}
}
//OnOptoReceived(this, new OptoReceivedEventArgs(s));
}
else
{
//OnOptoReceived(this, new OptoReceivedEventArgs("."));
}
}
// lock (this)
// {
//
// }
}
public string ReadOptoData()
{
if (optoSerialPort is null) return "";
string received = ".";
lock (this)
{
int nrBytes = optoSerialPort.BytesToRead;
if (nrBytes > 0)
{
char[] buffer = new char[nrBytes];
optoSerialPort.Read(buffer, 0, nrBytes);
received = new string(buffer);
}
}
// lock (this)
// {
//
// }
return received;
}
void OptoTelegramReceived(int currentIx, bool async, Int64 volumeRawExt, Int64 timestampRawExt)
{
currentTelegramIx = currentIx;
lastVolumeRaw = volumeRawExt;
lastTimestamp = timestampRawExt;
if (volumeLtr == 0 && volumeLtr0 == 0)
{
volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0;
volumeLtr0 = volumeLtr;
}
else
{
volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0;
}
if (timestampSec == 0 && timestampSec0 == 0)
{
timestampSec = (double)lastTimestamp / 8192.0;
timestampSec0 = timestampSec;
}
else
{
timestampSec = (double)lastTimestamp / 8192.0;
}
}
/// <summary>
@@ -1002,12 +947,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
void ReadPulses()
{
beginWMState = volumeLtr0;
endWMState = volumeLtr;
TimeSpan delta = _lastSampleTime - _firstSampleTime;
double volume = _averageFlow * (delta.TotalMilliseconds / 1000);
//log.Debug("ReadPulses - Calculated Value:" + volume);
beginWMState = 1;
endWMState = beginWMState + volume ;
wmVolume = Math.Abs(endWMState - beginWMState);
wmPulses = (int)(wmVolume * (double)PulsesPerLtr + 0.5);
wmRefPulses = StateMachine.ControlBoardMain.RefPulses;
wmTestTime = timestampSec - timestampSec0;
wmTestTime = delta.TotalSeconds;
}
private void OpenOptoSerialPort(string comPort, int baudRate, Parity parity, int dataBits, StopBits stopBit, Handshake handshake)
@@ -1018,6 +966,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
/// Open serial port: 9600 Bd, 8 data bits, 1 stop bit, no parity
try
{
CloseOptoSerialPort();
optoSerialPort = new SerialPort(comPort, baudRate, parity, dataBits, stopBit);
optoSerialPort.Handshake = handshake;
@@ -1039,12 +988,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
private void CloseOptoSerialPort()
{
if (optoSerialPort != null)
if (_optoHeadService != null)
{
optoSerialPort.Close();
optoSerialPort = null;
_optoHeadService.CloseSerialConnection();
_optoHeadService = null;
log.FatalFormat($"{Name} OptoPort closed: {this}");
}
communication.OpticalHeadTest.SetActiveMode(_poseidonCfg);
}
@@ -1056,10 +1008,14 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
{
try
{
OpenOptoSerialPort($"COM{_poseidonCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One, Handshake.None);
//set test mode via the cli
communication.OpticalHeadTest.SetTestMode(_poseidonCfg);
//open opto serial port
OpenOptoConnection(_poseidonCfg);
}
catch (Exception)
catch (Exception e)
{
log.Error($"{Name} OptoPort - error opening port: {_poseidonCfg.OptoComPortNr}, Details: {e.Message}");
}
/// Reset opto-data, etc.
optoDataCount = 0;
@@ -1482,8 +1438,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
volumeLtr = 0;
volumeLtr0 = 0;
timestampSec = 0;
timestampSec0 = 0;
extraDataPath = null;
@@ -2,6 +2,8 @@ using System;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using log4net;
using TBF.Rig.Output.Printers.Label;
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils;
using CliRunner = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.CliRunnerOld;
using OptoHeadStatus = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus;
@@ -13,6 +15,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
public class NfcHeadServiceOld
{
private static readonly ILog log = LogManager.GetLogger(typeof(NfcHeadServiceOld));
private bool activeHandlerSessioEnabled = false;
private CliRunner _cliRunner;
@@ -208,7 +211,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
}
else
{
throw new Exception($"Failed to parse OptoHeadStatus from output. Result: {result}");
log.Error($"Failed to parse OptoHeadStatus from output. Result: {result}");
//throw new Exception($"Failed to parse OptoHeadStatus from output. Result: {result}");
}
}
@@ -1,6 +1,10 @@
using System;
using System.IO.Ports;
using System.Threading.Tasks;
using Common;
using log4net;
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols;
using TBF.Rig.Sequences;
using SERIAL_Driver = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.SERIAL_Driver;
using WaterMetrologyData = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.WaterMetrologyData;
@@ -8,9 +12,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
{
public class OptoHeadService
{
static readonly ILog log = LogManager.GetLogger("PoseidonConnection");
public class Con
{
public string com = "COM5";
public int baudrate = 38400;
public int dataBits = 8;
@@ -18,6 +24,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
public StopBits stopbits = StopBits.Two;
public int readTimeout = 5000;
public int writeTimeout = 1000;
private DebugMode _debugLevel;
public DebugMode DebugModeSetting { get => _debugLevel; }
public Con(string com, int baudrate, int dataBits, Parity parity, StopBits stopbits, int readTimeout,
int writeTimeout) : this(com)
@@ -29,10 +37,23 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
public Con(DebugMode debugLevel,string com, int baudrate, int dataBits, Parity parity, StopBits stopbits, int readTimeout,
int writeTimeout) : this(com)
{
this._debugLevel = debugLevel;
this.baudrate = baudrate;
this.dataBits = dataBits;
this.parity = parity;
this.stopbits = stopbits;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
public Con(string com)
public Con(string com, DebugMode debugLevel = DebugMode.Normal)
{
this.com = com;
this._debugLevel = debugLevel;
}
}
@@ -55,11 +76,19 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
OnOptoReceivedHandler = null;
bool isopen = false;
Con con = Connection;
if (con == null)
{
return false;
}
byte[] message = {0x00};
byte[] bytesReceived;
if (!driver.isOpen())
if (con?.DebugModeSetting == DebugMode.Simulate)
{
isopen = true;
}
else if (!driver.isOpen())
{
isopen = driver.OpenConnection(
@@ -72,6 +101,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
con.writeTimeout);
}
_bRunStarted = false;
return isopen;
}
@@ -79,24 +110,39 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
{
dissableRunLoop = true;
OnOptoReceivedHandler = null;
driver.Close();
OnOptoReceivedHandler = null;
if (Connection?.DebugModeSetting != DebugMode.Simulate)
{
driver.Close();
}
_bRunStarted = false;
}
private EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs> OnOptoReceivedHandler;
public bool IsRunning
{
get { return !dissableRunLoop
&& ((Connection?.DebugModeSetting != DebugMode.Simulate) ? driver.isOpen() : true)
&& _bRunStarted;}
}
public void RunLoop(EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs> onOptoReceivedHandler)
{
log.Debug("RunLoop started on event!");
OnOptoReceivedHandler = onOptoReceivedHandler;
Task.Run(() => Run());
}
public void RunLoop()
{
log.Debug("RunLoop started!");
Task.Run(() => Run());
}
private bool dissableRunLoop = false;
private bool _bRunStarted = false;
/// <summary>
/// Run the service. Catch one communication to WaterMetrologyData field.
/// </summary>
@@ -104,10 +150,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
{
while (!dissableRunLoop)
{
_bRunStarted = true;
WaterMetrologyData = ParseData(RunReading());
if (OnOptoReceivedHandler != null && WaterMetrologyData != null)
{
OnOptoReceivedHandler.Invoke(this, new CommonRR.IPerl.communication.OptoReceivedEventArgs(WaterMetrologyData.ToString()));
log.Debug($"Received OptoData: {WaterMetrologyData}");
OnOptoReceivedHandler?.Invoke(this, new CommonRR.IPerl.communication.OptoReceivedEventArgs(WaterMetrologyData?.ToString(), WaterMetrologyData));
}
}
@@ -115,13 +163,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
byte[] RunReading()
{
if (Connection?.DebugModeSetting != DebugMode.Simulate)
{
return new byte[] {0x00};
}
if (driver.isOpen())
{
driver.SendMessage(new byte[] {0x00}, 1);
return driver.GetRawData();
byte[] rawData = driver.GetRawData();
log.Debug($"Received data size: {rawData?.Length ?? 0} bytes, raw data: {(rawData==null? "" :BitConverter.ToString(rawData))}");
return rawData;
}
else
{
log.Debug("Serial port is not open.");
dissableRunLoop = true;
}
@@ -130,6 +185,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
public WaterMetrologyData ParseData(byte[] data)
{
if (Connection?.DebugModeSetting != DebugMode.Simulate)
{
return WaterMetrologyData.SimulateC7();
}
try
{
if (data == null || data.Length == 0)
@@ -37,6 +37,21 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
return waterMetrologyData;
}
public static WaterMetrologyData SimulateC7()
{
WaterMetrologyData waterMetrologyData = new WaterMetrologyData();
waterMetrologyData.c7Data = WaterMetrologyDataC7.Simulate();
return waterMetrologyData;
}
public static WaterMetrologyData SimulateC2()
{
WaterMetrologyData waterMetrologyData = new WaterMetrologyData();
waterMetrologyData.c2Data = WaterMetrologyDataC2.Simulate();
return waterMetrologyData;
}
public override string ToString()
{
return $"Status: {_optoHeadStatus}, C7Data: {c7Data}, C2Data: {c2Data}";
@@ -21,7 +21,17 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
public bool FastHPFC { get; set; }
public bool FieldPolarity { get; set; }
public bool ImpedancePolarity { get; set; }
public double FlowRateLPerS // Flow Rate in L/s metric units
{
get
{
double flowRateGPM = FlowRate / 10000; //investigation flow meter GPM
double flowRateLPerS = flowRateGPM * 0.063090196432096 ; // conversion factor from GPM to L/s with minimal digit lost
return flowRateLPerS;
}
}
public double CalcFlowmLps
{
get { return FlowRate / 4.0; } // FlowRate is in 1/4 mL/s
@@ -41,6 +51,32 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
return Parse(data, dt, dutinfo);
}
public static WaterMetrologyDataC2 Simulate()
{
var result = new WaterMetrologyDataC2();
result.DutInfo = "dutinfo";
result.Dt = DateTime.Now;
result.AdcSample = 1;
result.LastField = 2;
result.FlowRate = 12456;
result.Accumulator = 789465;
result.FlipPeriod = 1;
result.VinfStart = 0;
result.VinfEnd = 0;
result.ElectrodeDelta = 1;
result.Impedance = 1;
result.FieldDriveTime = 0x00 ;
result.IsInLowFlow = false;
result.IsInEmptyPipe = false;
result.FastHPFC = false; // Fast High Pass Filter Constant in bit 2
result.FieldPolarity = false; // Field Polarity in bit 3
result.ImpedancePolarity = false; // Impedance Polarity in bit 4
return result;
}
public static WaterMetrologyDataC2 Parse(byte[] data, DateTime dt, string dutinfo)
{
if (data.Length < 24)
@@ -23,6 +23,47 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
public bool IsLearningActive { get; set; }
public bool AdcShiftsUpdated { get; set; }
public static WaterMetrologyDataC7 Simulate()
{
var result = new WaterMetrologyDataC7();
result.DutInfo = "dutinfo";
result.Dt = DateTime.Now;
result.AdcSample = 1;
result.LastField = 2;
result.FlowRate = 12456;
result.Accumulator = 789465;
result.FlipPeriod = 1;
result.VinfStart = 0;
result.VinfEnd = 0;
result.ElectrodeDelta = 1;
result.Impedance = 1;
result.FieldDriveTime = 0x00 ;
result.IsInLowFlow = false;
result.IsInEmptyPipe = false;
result.FastHPFC = false; // Fast High Pass Filter Constant in bit 2
result.FieldPolarity = false; // Field Polarity in bit 3
result.ImpedancePolarity = false; // Impedance Polarity in bit 4
result.MagTamperState = true; // bits 5 and 6 represent MagTamperState
result.IsLearningActive = true; // bit 7 represents IsLearningActive
result.AdcShiftsUpdated = false; // bit 0 represents AdcShiftsUpdated
result.LastFieldmilliGauss = 0;
result.ImpedanceI = 0; // in phase
result.ImpedanceQ = 0; // out of phase
result.NoiseMetric = 0; //
result.LearningLockout = 0;
result.ReverseBuffer = 0;
result.ConditionedAdc = 0;
result.Totalalizer = 0;
return result;
}
public static WaterMetrologyDataC7 Parse(string base64Data, DateTime dt, string dutinfo)
{
@@ -6,6 +6,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
{
[Description("..")] None,
[Description("Nfc")] Nfc,
[Description("Touch Capl")]Touched,
[Description("cTouchRead")]Touched,
}
}
@@ -17,6 +17,9 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
internal class OpticalHeadTest
{
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
DebugMode _debugMode;
public DebugMode DebugMode { get => _debugMode; set => _debugMode = value; }
internal static string OpenSealing(ISmartReader iHead)
{
@@ -26,6 +29,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
internal static string ReadRequest_SerialNo(PoseidonCfg iHeadCfg)
{
if (iHeadCfg != null && iHeadCfg.DebugLevel == DebugMode.Simulate)
{
return "1111";
}
string serialNo = null;
try
{
@@ -77,6 +85,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
internal static string SetActiveMode(PoseidonCfg iHeadCfg)
{
if (iHeadCfg != null && iHeadCfg.DebugLevel == DebugMode.Simulate)
{
return "OK";
}
SerialPortData serialPortData = new SerialPortData(
$"COM{iHeadCfg.RfidComPortNr}",
iHeadCfg.CliProgramName,
@@ -100,6 +113,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
internal static string SetTestMode(PoseidonCfg iHeadCfg)
{
if (iHeadCfg != null && iHeadCfg.DebugLevel == DebugMode.Simulate)
{
return "OK";
}
SerialPortData serialPortData = new SerialPortData(
$"COM{iHeadCfg.RfidComPortNr}",
iHeadCfg.CliProgramName,
@@ -123,6 +141,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
public static void Deactivate()
{
if (_lastIHeadCfg != null && _lastIHeadCfg.DebugLevel == DebugMode.Simulate)
{
return;
}
StopOptoTestInputLoop();
if (_lastOptoHeadStatus != OptoHeadStatus.Unknown &&
_lastOptoHeadStatus != OptoHeadStatus.OptoHeadDisabled &&
@@ -142,7 +164,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
{
if (optoHeadService != null) return false;
OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}");
OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}", iHeadCfg.DebugLevel);
optoHeadService = new OptoHeadService(connection);
optoHeadService.CreateSerialConnection();
optoHeadService.RunLoop(onOptoReceivedHandler);
@@ -17,7 +17,18 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.implementations
public class PoseidonReader : ComponentBase, IDevice, IRegReaderDatastream, ISessionDataMngmnt, IOperation, ISmartReader
{
private static readonly ILog log = LogManager.GetLogger(typeof(PoseidonReader));
public PoseidonReader()
{
_pulsesPerLtr = 0;
_ltrsPerPulse = 0;
_wmPulses = 0;
_wmRefPulses = 0;
_wmVolume = 0;
_beginWmState = 0;
_endWmState = 0;
}
public override string ToString()
{
return string.Format("{0}({1})", ClassName, Cfg.ToString(-1));
@@ -101,13 +112,23 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.implementations
throw new System.NotImplementedException();
}
public double PulsesPerLtr { get; }
public double LtrsPerPulse { get; }
public int WMPulses { get; }
public int WMRefPulses { get; }
public double WMVolume { get; }
public double BeginWMState { get; }
public double EndWMState { get; }
private double _pulsesPerLtr ;
private double _ltrsPerPulse ;
private int _wmPulses ;
private int _wmRefPulses ;
private double _wmVolume ;
private double _beginWmState ;
private double _endWmState ;
public double PulsesPerLtr { get => _pulsesPerLtr; }
public double LtrsPerPulse { get => _ltrsPerPulse; }
public int WMPulses { get => _wmPulses; }
public int WMRefPulses { get =>_wmRefPulses; }
public double WMVolume { get =>_wmVolume; }
public double BeginWMState { get => _beginWmState; set => _beginWmState = value; }
public double EndWMState { get => _endWmState; set => _endWmState = value; }
public IOperation ReadDatastreamOp()
{
throw new System.NotImplementedException();
+2
View File
@@ -14,6 +14,8 @@ namespace TBF.Rig.Scales.MettlerToledo
public IComponent DummyComponent() { return new Scale(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Scale(cfg); }
// wrapping to use in unit tests
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components, ISerialPort serialPort) { return new Scale(cfg, serialPort); }
public IComponentCfg DefaultConfig() { return new ScaleCfg("WT", this); }
@@ -0,0 +1,14 @@
using System.IO.Ports;
namespace TBF.Rig.Scales.MettlerToledo
{
public interface ISerialPort
{
void Open();
void Close();
void Write(string text);
string ReadExisting();
bool IsOpen { get; }
Handshake Handshake { get; set; }
}
}
+10 -2
View File
@@ -50,7 +50,7 @@ namespace TBF.Rig.Scales.MettlerToledo
///
public IDrawingItem DrawingItem { get { return scaleCfg as IDrawingItem; } }
protected SerialPort serialPort;
protected ISerialPort serialPort;
protected StringBuilder stringBuilder;
/// <summary>The state of the mass measurement</summary>
@@ -93,6 +93,13 @@ namespace TBF.Rig.Scales.MettlerToledo
{
scaleCfg = cfg as ScaleCfg;
}
public Scale(Generic.IComponentCfg cfg, ISerialPort serialPort)
: base(cfg)
{
scaleCfg = cfg as ScaleCfg;
this.serialPort = serialPort;
}
public override void Initialize()
{
@@ -111,7 +118,8 @@ namespace TBF.Rig.Scales.MettlerToledo
if (scaleCfg.DebugLevel == DebugMode.Normal)
{
string comPortName = "COM" + scaleCfg.ComPortNr.ToString();
serialPort = new SerialPort(comPortName, scaleCfg.BaudRate, scaleCfg.Parity, scaleCfg.DataBits, scaleCfg.StopBits);
serialPort ??= new SerialPortDevice(comPortName, scaleCfg.BaudRate, scaleCfg.Parity, scaleCfg.DataBits,
scaleCfg.StopBits);
serialPort.Handshake = scaleCfg.Handshake;
serialPort.Open();
log.FatalFormat("{0} - Device successfully initialized", Name);
@@ -0,0 +1,13 @@
using System.IO.Ports;
namespace TBF.Rig.Scales.MettlerToledo
{
public class SerialPortDevice : SerialPort, ISerialPort
{
public SerialPortDevice(string comPortName, int scaleCfgBaudRate, Parity scaleCfgParity, int scaleCfgDataBits, StopBits scaleCfgStopBits)
: base(comPortName, scaleCfgBaudRate, scaleCfgParity, scaleCfgDataBits, scaleCfgStopBits)
{
}
}
}
@@ -0,0 +1,84 @@
using System.IO.Ports;
using log4net;
using log4net.Core;
using log4net.Repository.Hierarchy;
using NHibernate;
namespace TBF.Rig.Scales.MettlerToledo
{
public class SerialPortDeviceFake : ISerialPort
{
// write dirrectly into cmd
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private bool bIsOpen = false;
public void Open()
{
log.Debug( "SerialPortDeviceFake.Open()");
bIsOpen = true;
}
public void Close()
{
log.Debug( "SerialPortDeviceFake.Close()");
bIsOpen = false;
}
private string lastWrite = "";
private string lastRead = "";
public string LastWrite { get => lastWrite; set => lastWrite = value;}
public string LastRead { get => lastRead; set => lastRead = value;}
public void Write(string text)
{
log.DebugFormat("SerialPortDeviceFake.Write({0})", text);
lastWrite = text;
}
private string forcedText = null;
public void ForceReturnAnswer(string text)
{
forcedText = text;
}
public string ReadExisting()
{
string result = "", end = "\r\n";
if (forcedText != null)
{
result = forcedText;
forcedText = null;
return result + end;
}
if (!string.IsNullOrEmpty(lastWrite))
{
if (lastWrite.Contains("S"+end))
{
result = "S D 170.725 kg"; // correct stable scale mass answer
}
else if (lastWrite.Contains("R"))
{
result = "RD";
}
//store result
if (!string.IsNullOrEmpty(result))
{
result = result + end;
lastRead = result;
}
}
return result;
}
public bool IsOpen
{
get { return bIsOpen; }
}
Handshake handshakeVal = Handshake.None;
public Handshake Handshake { get => handshakeVal; set => handshakeVal = value; }
}
}
+6 -3
View File
@@ -57,7 +57,11 @@ namespace TBF.Rig.Sequences
try
{
/// 1nd argument
ITestMethodCfg iPerlCfgIPerl = cfg as ITestMethodCfg;
ITestMethodCfg testMethodCfg = cfg as ITestMethodCfg;
if (testMethodCfg == null)
{
}
/// 2rd argument: as is
@@ -68,8 +72,7 @@ namespace TBF.Rig.Sequences
/*myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm(iPerlCfg, tests, iPerlCommParams);
myRef.modelessDlg.Show();*/
myRef.modelessDlg = new SmartCommunicationForm(
testMethod , tests, iPerlCommParams);
myRef.modelessDlg = new SmartCommunicationForm( testMethod , tests, iPerlCommParams);
myRef.modelessDlg.Show();
}
catch (Exception e)
+16
View File
@@ -323,6 +323,22 @@ namespace TBF.Rig
}
}
[Obsolete("Use InitializeBoardEtc() instead.")]
public static void InitializeBoardEtc_Fake(IList<IComponent> componentList)
{
components = componentList;
// base find components - find control board!, ...
foreach (var cmpnt in components)
{
if (cmpnt is ControlBoard.IControlBoard) ControlBoardMain = cmpnt as ControlBoard.IControlBoard;
if (cmpnt is IBenchInfo) ProcessData.BenchInfo = cmpnt as IBenchInfo;
if (cmpnt is IErrorFlags) ProcessData.ErrorFlagsComp = cmpnt as IErrorFlags;
if (cmpnt is IStatisticsMonitoring)
ProcessData.StatisticsMonitoringComp = cmpnt as IStatisticsMonitoring;
}
}
public static string CurrentlyInitializedComponentName;
///
+1
View File
@@ -210,6 +210,7 @@ namespace TBF.Rig
new TestMethods.StandingStartMassCollection.Single.Factory(),
new TestMethods.StandingStartMassCollection.Compound.Factory(),
new TestMethods.StandingStartMassCollection.HeatMeters.Factory(),
new TestMethods.StandingStartMassCollectionPoseidon.Single.Factory(),
new TestMethods.StandingStartMassCollectionAdvance.Single.Factory(),
new TestMethods.StandingStartMassCollectionAdvance.Compound.Factory(),
new TestMethods.StandingStartMassCollectionAdvance.HeatMeters.Factory(),
@@ -373,7 +373,7 @@ namespace TBF.Rig.TestMethods.SmartMeterFlyingStartMassCollection
/// Show the modeless dialog with error indication
///
string componentName = (method as IComponent)?.Name ?? string.Empty;
Program.MainWnd.Invoke(new SmartCommFormDlgt(OpenSmartCommForm), new object[] { this, componentName, test, testParams });
Program.MainWnd.Invoke(new SmartCommFormDlgt(OpenSmartCommForm), new object[] { this, method, test, testParams });
//------------------------------------------------
Bridge.OnActivity(this, Strings.iPerl_Communication_in_progress);
@@ -9,6 +9,7 @@ using Common;
using TBF.Boxes;
using TBF.Resources;
using TBF.Rig.GenericDevices;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using TBF.UiBridge;
namespace TBF.Rig.TestMethods.StandingStart
@@ -511,6 +512,9 @@ namespace TBF.Rig.TestMethods.StandingStart
for (int i = 0; i < waterMetersCount; i++)
{
GenericDevices.IRegReader rr = sensPath.RegisterReaders[i];
if (rr is ICommonRegReader)
(rr as ICommonRegReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
if (rr is Rig.RegisterReaders.StandingStartStop.RegisterReader)
(rr as Rig.RegisterReaders.StandingStartStop.RegisterReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
@@ -762,7 +766,10 @@ namespace TBF.Rig.TestMethods.StandingStart
for (int i = 0; i < Data.WMsCount; i++)
{
GenericDevices.IRegReader rr = sensPath.RegisterReaders[i];
if (rr is ICommonRegReader)
(rr as ICommonRegReader).EndWMState = dataEntryCmpnt.WMEndState(i);
if (rr is Rig.RegisterReaders.StandingStartStop.RegisterReader)
(rr as Rig.RegisterReaders.StandingStartStop.RegisterReader).EndWMState = dataEntryCmpnt.WMEndState(i);
@@ -1010,6 +1017,13 @@ namespace TBF.Rig.TestMethods.StandingStart
&& (tstRslt.ErrorFlags == 0);
meterRslt.TestDone = true;
tstRslt.TestDone = true;
if (regReader is ICommonRegReader regReaderCommon)
// if (meterRslt.WaterMeter != null
// && tstRslt is ICommonRegReader tstRsltCommon
// && !string.IsNullOrEmpty(tstRsltCommon.SerialNr))
{
meterRslt.WaterMeter.SerialNr = regReaderCommon.SerialNr;
}
}
}
}
@@ -11,6 +11,7 @@ using Config.Entities;
using TBF.Boxes;
using TBF.Resources;
using TBF.Rig.GenericDevices;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using TBF.UiBridge;
namespace TBF.Rig.TestMethods.StandingStartMassCollection
@@ -559,7 +560,6 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection
State.Create(string.Format("{0}({1}) : Enter start states of water meters", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperations(readTempPressOps)
.AddOperation(readStartMassOp)
.AddOperation(testInProgress)
.AddOperation((dataEntryCmpnt as GenericDevices.IHasWMStatesForm).ShowTestStartFormOp(sensPath.RegisterReaders))
.AddOperation(processDataLoggingOp)
@@ -594,8 +594,15 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection
{
for (int i = 0; i < waterMetersCount; i++)
{
IRegReader rr = sensPath.RegisterReaders[i];
if (rr is ICommonRegReader)
{
(rr as ICommonRegReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
}
if (rr is Rig.RegisterReaders.StandingStartStop.RegisterReader)
(rr as Rig.RegisterReaders.StandingStartStop.RegisterReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
@@ -641,6 +648,28 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection
}
}
}
//...MF...kvapkania... robime to pridanim casovej konstanty, ktora sa konfiguruje
State.Create(string.Format("{0}({1}) : Measure the start mass", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperations(readTempPressOps)
.AddOperation(testInProgress)
.AddOperation(scale.ReadStableMassOp(ref StartMass, test.TimeFlow2Mass, test.MassMethod, test.MassRepeats, test.MassSpread))
.AddOperation(processDataLoggingOp)
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
if (e.Contains(Event.Error)) { retVal = Event.Error; goto stopTest; }
if (TestAndLogUiCmdStop(test, e)) { retVal = Event.UiCmdStop; goto stopTest; }
if (e.Contains(Event.ScaleTimeout))
{
Bridge.OnError(this, Strings.Mass_measurement_timeout);
retVal = Event.RecoverableError;
goto stopTest;
}
}
while (!e.Contains(Event.ScaleDone) && !e.Contains(Event.Next));
}
else
{
@@ -648,7 +677,8 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection
.AddOperation(checkUiOp)
.AddOperations(readTempPressOps)
.AddOperation(testInProgress)
.AddOperation(readStartMassOp)
//.AddOperation(readStartMassOp)
.AddOperation(scale.ReadStableMassOp(ref StartMass, test.TimeFlow2Mass, test.MassMethod, test.MassRepeats, test.MassSpread))
.AddOperation(processDataLoggingOp)
.EnterState();
do {
@@ -929,6 +959,10 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection
for (int i = 0; i < waterMetersCount; i++)
{
GenericDevices.IRegReader rr = sensPath.RegisterReaders[i];
if (rr is ICommonRegReader)
(rr as ICommonRegReader).EndWMState = dataEntryCmpnt.WMEndState(i);
if (rr is Rig.RegisterReaders.StandingStartStop.RegisterReader)
(rr as Rig.RegisterReaders.StandingStartStop.RegisterReader).EndWMState = dataEntryCmpnt.WMEndState(i);
@@ -977,7 +1011,34 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection
}
}
}
}
//...MF...kvapkanie
//------------------------------------------------
Bridge.OnActivity(this, Strings.Measuring_the_weight);
//------------------------------------------------
State.Create(string.Format("{0}({1}) : Measuring the end mass", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperations(readTempPressOps)
.AddOperation(testInProgress)
.AddOperation(scale.ReadStableMassOp(ref EndMass, test.TimeStop2Mass, test.MassMethod, test.MassRepeats, test.MassSpread))
.AddOperation(new Operations.TimerOp(StableMassMsrmntTimeoutSec))
.AddOperation(processDataLoggingOp)
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
if (e.Contains(Event.Error)) { retVal = Event.Error; goto stopTest; }
if (TestAndLogUiCmdStop(test, e)) { retVal = Event.UiCmdStop; goto stopTest; }
if (e.Contains(Event.ScaleTimeout))
{
Bridge.OnError(this, Strings.Mass_measurement_timeout);
retVal = Event.RecoverableError;
goto stopTest;
}
}
while (!e.Contains(Event.ScaleDone) && !e.Contains(Event.Next));
///
}
//------------------------------------------------
Bridge.OnActivity(this, Strings.Test_completed);
@@ -1197,6 +1258,14 @@ namespace TBF.Rig.TestMethods.StandingStartMassCollection
&& (tstRslt.ErrorFlags == 0);
meterRslt.TestDone = true;
tstRslt.TestDone = true;
if (regReader is ICommonRegReader regReaderCommon)
// if (meterRslt.WaterMeter != null
// && tstRslt is ICommonRegReader tstRsltCommon
// && !string.IsNullOrEmpty(tstRsltCommon.SerialNr))
{
meterRslt.WaterMeter.SerialNr = regReaderCommon.SerialNr;
}
}
}
}
@@ -0,0 +1,39 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using Common;
using Config.Entities;
using log4net;
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.Compound
{
public class Component : ComponentBase, GenericDevices.ITestMethod
{
private static readonly ILog log = LogManager.GetLogger(typeof(Component));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
public bool CanTest(MetersKind meters) { return meters == MetersKind.Combined; }
public bool DoTransitions() { return true; }
public bool CheckDeviceCaps(Test test, OutputPath devices, out string message)
{
return StandingStartMassCollection.StandingStartMassCollectionSeq.CheckDeviceCaps(test, devices, out message);
}
public Component() { }
///
public Component(Generic.IComponentCfg cfg)
: base(cfg)
{
log.Warn(this.ToString());
}
///
public override void Initialize() { }
public IList<Event> Execute(Test test, int repetNr, bool isLastRepetition)
{
return (new StandingStartMassCollection.StandingStartMassCollectionSeq()).Execute(test, repetNr, isLastRepetition, true, null, DebugLevel);
}
}
}
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Configs.NameOnly;
using TBF.Rig.Generic;
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.Compound
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public IComponent DummyComponent() { return new StandingStartMassCollection.Compound.Component(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new StandingStartMassCollection.Compound.Component(cfg); }
public IComponentCfg DefaultConfig() { return new TestMethodCfg(this.GetType().Namespace.Substring(20), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(TestMethodCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,43 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using Common;
using Config.Entities;
using log4net;
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.HeatMeters
{
public class Component : ComponentBase, GenericDevices.ITestMethod
{
private static readonly ILog log = LogManager.GetLogger(typeof(Component));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
public bool CanTest(MetersKind meters) { return meters == MetersKind.HeatMeter; }
public bool DoTransitions() { return true; }
public bool CheckDeviceCaps(Test test, OutputPath devices, out string message)
{
return StandingStartMassCollection.StandingStartMassCollectionSeq.CheckDeviceCaps(test, devices, out message);
}
readonly TestMethodCfg testMethodCfg;
public Component() { }
///
public Component(Generic.IComponentCfg cfg)
: base(cfg)
{
testMethodCfg = cfg as TestMethodCfg;
log.Warn(this.ToString());
}
///
public override void Initialize() { }
public IList<Event> Execute(Test test, int repetNr, bool isLastRepetition)
{
return (new StandingStartMassCollectionPoseidon.StandingStartMassCollectionPoseidonSeq()).Execute(test, repetNr, isLastRepetition, false, testMethodCfg.TestParams, DebugLevel);
}
}
}
@@ -0,0 +1,26 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.HeatMeters
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public IComponent DummyComponent() { return new StandingStartMassCollection.HeatMeters.Component(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new StandingStartMassCollection.HeatMeters.Component(cfg); }
public IComponentCfg DefaultConfig() { return new TestMethodCfg(this.GetType().Namespace.Substring(20), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(TestMethodCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,49 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using System.Xml.Serialization;
using Common;
using Config.Entities;
using TBF.Rig.Generic;
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.HeatMeters
{
public class TestMethodCfg : ComponentCfgBase, Generic.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(); }
/// <summary> Test parameters </summary>
[XmlIgnore]
public TestParams TestParams;
public override IParamsProvider GetRuntimeTestParamsProvider() { return TestParams; }
public override IParamsProvider CreateTestParamsProvider() { return new TestParams(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()
{
TestParams = new TestParams(true);
}
public TestMethodCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = string.Empty;
}
public string ToString(int i)
{
return string.Format("Name={0}", Name);
}
}
}
@@ -0,0 +1,70 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System;
using System.Windows.Forms;
using Common;
using TBF.Rig.Generic;
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.HeatMeters
{
public partial class TestMethodCfgCtrl : UserControl, IComponentCfgCtrl
{
public bool ShowMore { get { return false; } }
StandingStartMassCollection.HeatMeters.TestMethodCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as StandingStartMassCollection.HeatMeters.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;
}
public void Unlock()
{
nameTextBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
return flags;
}
}
}
@@ -0,0 +1,86 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.HeatMeters
{
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.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(137, 57);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 5;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(27, 60);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 4;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(134, 33);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 3;
this.classNameLabel.Text = "ComonentName";
//
// BasicPrinterCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "BasicPrinterCfgCtrl";
this.Size = new System.Drawing.Size(300, 200);
this.Load += new System.EventHandler(this.EntryFormCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
}
}
@@ -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>
@@ -0,0 +1,197 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System.IO;
using System.Xml.Serialization;
using Common;
using Config.Entities;
using TBF.Resources;
using TBF.Rig.Generic;
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.HeatMeters
{
public class TestParams : TestParamsBase, IParamsProvider, ITestParams
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TestParams) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public float ErrorLimitLo; /// [%]
public float ErrorLimitHi; /// [%]
public bool EvaluateVolume; /// true = evaluate also the volume, false = evaluate only energy
public float TempWarmLo; /// Low limit for warm temperature [°C]
public float TempWarmHi; /// High limit for warm temperature [°C]
public float TempColdLo; /// Low limit for cold temperature [°C]
public float TempColdHi; /// High limit for cold temperature [°C]
public bool FlowMeasuredAtHiTempPipe; /// true = flow measured at high temp. pipe, false = flow measured at low temp. pipe
public float DeltaTempWarm;
public float DeltaTempCold;
public float ChangeInTimeWarm;
public float ChangeInTimeCold;
public string Prompt;
public override void InitializeAll()
{
FlowMeasuredAtHiTempPipe = false;
}
string[] paramNames = new string[]
{
Strings.Err_limit_neg_pct_chdr,
Strings.Err_limit_pos_pct_chdr,
Strings.Evaluate_volume,
"T hi min",
"T hi max",
"T lo min",
"T lo max",
"Flow measured at high temp.pipe",
"Delta T warm",
"Delta T cold",
"Change in time T warm",
"Change in time T cold",
Strings.Prompt,
};
public override string ParamName(int i) { return paramNames[i]; }
public override int ParamsCount() { return paramNames.Length; }
public override string ToString(int i)
{
switch (i)
{
case 0: return ErrorLimitLo.ToString();
case 1: return ErrorLimitHi.ToString();
case 2: return (EvaluateVolume ? Strings.yes : Strings.no);
case 3: return TempWarmLo.ToString();
case 4: return TempWarmHi.ToString();
case 5: return TempColdLo.ToString();
case 6: return TempColdHi.ToString();
case 7: return (FlowMeasuredAtHiTempPipe ? Strings.yes : Strings.no);
case 8: return DeltaTempWarm.ToString();
case 9: return DeltaTempCold.ToString();
case 10: return ChangeInTimeWarm.ToString();
case 11: return ChangeInTimeCold.ToString();
case 12: return Prompt;
default: return string.Empty;
}
}
public CfgUpdateFlags UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: ErrorLimitLo = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None;
case 1: ErrorLimitHi = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None;
case 2: EvaluateVolume = strValue.Equals(Strings.yes); return CfgUpdateFlags.None;
case 3: TempWarmLo = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None;
case 4: TempWarmHi = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None;
case 5: TempColdLo = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None;
case 6: TempColdHi = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None;
case 7: FlowMeasuredAtHiTempPipe = strValue.Equals(Strings.yes); return CfgUpdateFlags.None;
case 8: DeltaTempWarm = Utils.ParseUFloat(strValue); return CfgUpdateFlags.None;
case 9: DeltaTempCold = Utils.ParseUFloat(strValue); return CfgUpdateFlags.None;
case 10: ChangeInTimeWarm = Utils.ParseUFloat(strValue); return CfgUpdateFlags.None;
case 11: ChangeInTimeCold = Utils.ParseUFloat(strValue); return CfgUpdateFlags.None;
case 12: Prompt = strValue; return CfgUpdateFlags.None;
default: return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
float dummy;
switch (i)
{
case 0:
case 1:
case 3:
case 4:
case 5:
case 6:
if (Utils.TryParseSFloat(strValue, out dummy)) return true;
break;
case 2:
case 7:
if (strValue.Equals(Strings.yes) || strValue.Equals(Strings.no)) return true;
break;
case 8:
case 9:
case 10:
case 11:
if (Utils.TryParseUFloat(strValue, out dummy)) return true;
break;
case 12:
return true;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(TestParams prms)
{
prms.ErrorLimitLo = ErrorLimitLo;
prms.ErrorLimitHi = ErrorLimitHi;
prms.EvaluateVolume = EvaluateVolume;
prms.TempWarmLo = TempWarmLo;
prms.TempWarmHi = TempWarmHi;
prms.TempColdLo = TempColdLo;
prms.TempColdHi = TempColdHi;
prms.FlowMeasuredAtHiTempPipe = FlowMeasuredAtHiTempPipe;
prms.DeltaTempWarm = DeltaTempWarm;
prms.DeltaTempCold = DeltaTempCold;
prms.ChangeInTimeWarm = ChangeInTimeWarm;
prms.ChangeInTimeCold = ChangeInTimeCold;
prms.Prompt = Prompt;
}
public IParamsProvider Clone()
{
TestParams pars = new TestParams();
CopyContentTo(pars);
return pars;
}
public override void UpdateFromDbEntity(ComponentTest dbEntity)
{
if (dbEntity == null) return;
try
{
TestParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as TestParams;
testParamsEntity = dbEntity;
componentName = dbEntity.CmpntName;
test = dbEntity.Test;
if (tmp != null) tmp.CopyContentTo(this);
}
catch
{
}
}
/// <summary>
/// Parameterless constructor initializes the parameters
/// </summary>
public TestParams()
{
}
public TestParams(bool initialize)
{
if (initialize) InitializeAll();
}
public TestParams(ComponentTest testParamsEntity, string componentName, Test test)
{
this.testParamsEntity = testParamsEntity;
this.componentName = componentName;
this.test = test;
}
}
}
@@ -0,0 +1,39 @@
///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using Common;
using Config.Entities;
using log4net;
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.Single
{
public class Component : ComponentBase, GenericDevices.ITestMethod
{
private static readonly ILog log = LogManager.GetLogger(typeof(Component));
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 true; }
public bool CheckDeviceCaps(Test test, OutputPath devices, out string message)
{
return StandingStartMassCollection.StandingStartMassCollectionSeq.CheckDeviceCaps(test, devices, out message);
}
public Component() { }
///
public Component(Generic.IComponentCfg cfg)
: base(cfg)
{
log.Warn(this.ToString());
}
///
public override void Initialize() { }
public IList<Event> Execute(Test test, int repetNr, bool isLastRepetition)
{
return (new StandingStartMassCollection.StandingStartMassCollectionSeq()).Execute(test, repetNr, isLastRepetition, false, null, DebugLevel);
}
}
}
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2013-2016 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.Configs.NameOnly;
using TBF.Rig.Generic;
namespace TBF.Rig.TestMethods.StandingStartMassCollectionPoseidon.Single
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public IComponent DummyComponent() { return new StandingStartMassCollection.Single.Component(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new StandingStartMassCollection.Single.Component(cfg); }
public IComponentCfg DefaultConfig() { return new TestMethodCfg(this.GetType().Namespace.Substring(20).Replace(".Single", ""), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(TestMethodCfg.Serializer, component, this);
}
}
}
@@ -187,8 +187,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
///
public int WMPulses { get { return wmPulses; } }
public int WMRefPulses { get { return wmRefPulses; } }
public double BeginWMState { get { return beginWMState; } }
public double EndWMState { get { return endWMState; } }
public double BeginWMState { get { return beginWMState; } set { beginWMState = value; }}
public double EndWMState { get { return endWMState; } set { endWMState = value;} }
public double WMVolume { get { return wmVolume; } }
public double WMTestTime { get { return wmTestTime; } }
@@ -1,10 +1,16 @@
using TBF.Rig.Configs.NameOnly;
using TBF.Rig.Generic;
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
{
public interface ISmartTestMethod
{
public void MeterCommMilestone(int iItem, bool bValue);
public bool IsMeterCommMilestone(int iItem);
public ITestMethodCfg TestMethodCfg { get; }
}
}
@@ -135,7 +135,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
public static string SelectedTypeReader { get; set; }
private List<ICorrections> GetNewCorrectionList(ISmartTestMethod componentBase ,
TestMethodCfg cfg, IList<Test> tests, IList<ITestParams> multiTestParams)
ITestMethodCfg cfg, IList<Test> tests, IList<ITestParams> multiTestParams)
{
List<ICorrections> correctionsList = new List<ICorrections>();
@@ -154,7 +154,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
{
if (correctionsList.Any(x => x is SmartReader))
continue;
correctionsList.Add(new PoseidonCorrections(this));
correctionsList.Add(new PoseidonCorrections(this,log, rfidDataLogger, componentBase, cfg, tests, multiTestParams));
continue;
}
@@ -297,7 +297,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
ShuffleTextBoxes(ProcessData.WMsCount, ProcessData.LineSize);
this.ContextMenu = Correction.GetContextMenu();
//this.ContextMenu = Correction.GetContextMenu();
}
@@ -325,9 +325,11 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
{
checkBoxesEditMode = false;
ITestMethodCfg cfg = (componentBase as ITestMethodCfg);
ISmartTestMethod smartTestMethod = componentBase as ISmartTestMethod;
//TODO get corrections based on defined meter
_corrections = GetNewCorrectionList(componentBase as ISmartTestMethod,
componentBase.Cfg as TestMethodCfg, tests, multiTestParams);
_corrections = GetNewCorrectionList(smartTestMethod, smartTestMethod.TestMethodCfg, tests, multiTestParams);
InitializeMeterTypeItems();
UpdateHeads();
@@ -381,6 +383,27 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
private void UpdateHeads()
{
if (!(waterMeterPositions0 == null || waterMeterPositions0.Count <= 0)
&& labels != null && counters != null && messages != null && checkBoxes != null)
{
foreach (int position in waterMeterPositions0)
{
try
{
labels[position].Visible = false;
counters[position].Visible = false;
messages[position].Visible = false;
checkBoxes[position].Visible = false;
ckbIndex[position] = 0;
ckbState[position] = false;
}
catch (Exception e)
{
log.Error("UpdateHeads()", e);
}
}
}
iperlHeads?.Clear();
if (iperlHeads == null) iperlHeads = new List<ISmartReader>();
waterMeterPositions0?.Clear();
@@ -415,6 +438,21 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
if (wmPos >= ProcessData.WMsCount) break;
}
}
//we have items from the list, so we can enable the rows
if (iperlHeads.Count > 0)
{
WaterMetersCount = iperlHeads.Count;
ShuffleTextBoxes(WaterMetersCount, ProcessData.LineSize);
this.ContextMenu = Correction.GetContextMenu();
Correction.PrepareForTestsActivities(WaterMetersCount);
}
else
{
this.ContextMenu = null;
}
}
}
@@ -458,6 +496,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
/// this part works fine if we are on <b>test loop</b>
/// - because ProcessData.RegisterReaders is initialized in test loop
/// </summary>
/// <param name="selectedTypeReader"></param>
private static void InitializeSmartReaderLists()
{
iperlHeads = new List<ISmartReader>();
@@ -501,43 +540,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
/// <param name="lineSize">Number of watermeters in one line</param>
void ShuffleTextBoxes(int wmsCount, int lineSize)
{
labels = new Label[MaxTextBoxesCount]
{
wmLabel1, wmLabel2, wmLabel3, wmLabel4, wmLabel5, wmLabel6, wmLabel7, wmLabel8, wmLabel9, wmLabel10,
wmLabel11, wmLabel12, wmLabel13, wmLabel14, wmLabel15, wmLabel16, wmLabel17, wmLabel18, wmLabel19, wmLabel20,
wmLabel21, wmLabel22, wmLabel23, wmLabel24, wmLabel25, wmLabel26, wmLabel27, wmLabel28, wmLabel29, wmLabel30,
wmLabel31, wmLabel32, wmLabel33, wmLabel34, wmLabel35, wmLabel36, wmLabel37, wmLabel38, wmLabel39, wmLabel40,
wmLabel41, wmLabel42, wmLabel43, wmLabel44, wmLabel45, wmLabel46, wmLabel47, wmLabel48,
};
counters = new PictureBox[MaxTextBoxesCount]
{
pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6, pictureBox7, pictureBox8, pictureBox9, pictureBox10,
pictureBox11, pictureBox12, pictureBox13, pictureBox14, pictureBox15, pictureBox16, pictureBox17, pictureBox18, pictureBox19, pictureBox20,
pictureBox21, pictureBox22, pictureBox23, pictureBox24, pictureBox25, pictureBox26, pictureBox27, pictureBox28, pictureBox29, pictureBox30,
pictureBox31, pictureBox32, pictureBox33, pictureBox34, pictureBox35, pictureBox36, pictureBox37, pictureBox38, pictureBox39, pictureBox40,
pictureBox41, pictureBox42, pictureBox43, pictureBox44, pictureBox45, pictureBox46, pictureBox47, pictureBox48,
};
messages = new TextBox[MaxTextBoxesCount]
{
wmTextBox1, wmTextBox2, wmTextBox3, wmTextBox4, wmTextBox5, wmTextBox6, wmTextBox7, wmTextBox8, wmTextBox9, wmTextBox10,
wmTextBox11, wmTextBox12, wmTextBox13, wmTextBox14, wmTextBox15, wmTextBox16, wmTextBox17, wmTextBox18, wmTextBox19, wmTextBox20,
wmTextBox21, wmTextBox22, wmTextBox23, wmTextBox24, wmTextBox25, wmTextBox26, wmTextBox27, wmTextBox28, wmTextBox29, wmTextBox30,
wmTextBox31, wmTextBox32, wmTextBox33, wmTextBox34, wmTextBox35, wmTextBox36, wmTextBox37, wmTextBox38, wmTextBox39, wmTextBox40,
wmTextBox41, wmTextBox42, wmTextBox43, wmTextBox44, wmTextBox45, wmTextBox46, wmTextBox47, wmTextBox48,
};
checkBoxes = new CheckBoxImage[MaxTextBoxesCount]
{
checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5, checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10,
checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15, checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20,
checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25, checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30,
checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35, checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40,
checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45, checkBoxImage46, checkBoxImage47, checkBoxImage48,
};
ckbIndex = new int[MaxTextBoxesCount];
ckbState = new bool[MaxTextBoxesCount];
textBoxesCount = MaxTextBoxesCount;
InitializeTextBoxArrays();
///
if (wmsCount < textBoxesCount && lineSize > 0)
{
@@ -576,7 +579,56 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
ResizeDlgToFitEnabledControls();
}
void ResizeDlgToFitEnabledControls()
private void InitializeTextBoxArrays()
{
//if is initialized before we ignore initialization
if (labels != null
&& counters != null
&& messages != null
&& checkBoxes != null
&& ckbIndex != null
&& ckbState != null) return;
labels = new Label[MaxTextBoxesCount]
{
wmLabel1, wmLabel2, wmLabel3, wmLabel4, wmLabel5, wmLabel6, wmLabel7, wmLabel8, wmLabel9, wmLabel10,
wmLabel11, wmLabel12, wmLabel13, wmLabel14, wmLabel15, wmLabel16, wmLabel17, wmLabel18, wmLabel19, wmLabel20,
wmLabel21, wmLabel22, wmLabel23, wmLabel24, wmLabel25, wmLabel26, wmLabel27, wmLabel28, wmLabel29, wmLabel30,
wmLabel31, wmLabel32, wmLabel33, wmLabel34, wmLabel35, wmLabel36, wmLabel37, wmLabel38, wmLabel39, wmLabel40,
wmLabel41, wmLabel42, wmLabel43, wmLabel44, wmLabel45, wmLabel46, wmLabel47, wmLabel48,
};
counters = new PictureBox[MaxTextBoxesCount]
{
pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6, pictureBox7, pictureBox8, pictureBox9, pictureBox10,
pictureBox11, pictureBox12, pictureBox13, pictureBox14, pictureBox15, pictureBox16, pictureBox17, pictureBox18, pictureBox19, pictureBox20,
pictureBox21, pictureBox22, pictureBox23, pictureBox24, pictureBox25, pictureBox26, pictureBox27, pictureBox28, pictureBox29, pictureBox30,
pictureBox31, pictureBox32, pictureBox33, pictureBox34, pictureBox35, pictureBox36, pictureBox37, pictureBox38, pictureBox39, pictureBox40,
pictureBox41, pictureBox42, pictureBox43, pictureBox44, pictureBox45, pictureBox46, pictureBox47, pictureBox48,
};
messages = new TextBox[MaxTextBoxesCount]
{
wmTextBox1, wmTextBox2, wmTextBox3, wmTextBox4, wmTextBox5, wmTextBox6, wmTextBox7, wmTextBox8, wmTextBox9, wmTextBox10,
wmTextBox11, wmTextBox12, wmTextBox13, wmTextBox14, wmTextBox15, wmTextBox16, wmTextBox17, wmTextBox18, wmTextBox19, wmTextBox20,
wmTextBox21, wmTextBox22, wmTextBox23, wmTextBox24, wmTextBox25, wmTextBox26, wmTextBox27, wmTextBox28, wmTextBox29, wmTextBox30,
wmTextBox31, wmTextBox32, wmTextBox33, wmTextBox34, wmTextBox35, wmTextBox36, wmTextBox37, wmTextBox38, wmTextBox39, wmTextBox40,
wmTextBox41, wmTextBox42, wmTextBox43, wmTextBox44, wmTextBox45, wmTextBox46, wmTextBox47, wmTextBox48,
};
checkBoxes = new CheckBoxImage[MaxTextBoxesCount]
{
checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5, checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10,
checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15, checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20,
checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25, checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30,
checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35, checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40,
checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45, checkBoxImage46, checkBoxImage47, checkBoxImage48,
};
ckbIndex = new int[MaxTextBoxesCount];
ckbState = new bool[MaxTextBoxesCount];
textBoxesCount = MaxTextBoxesCount;
}
void ResizeDlgToFitEnabledControls()
{
int xMax = 0;
int yMax = 0;
@@ -645,7 +697,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
}
/// Start communication process by incrementing 'currentGroup'.
currentGroup++;
//currentGroup++;
int wtId = 0;
foreach (var wt in Correction.GetAllThreads())
@@ -869,6 +921,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
if (senderCombo == null) return;
SelectedTypeReader = senderCombo.SelectedItem?.ToString();
UpdateHeads();
SmartCommunicationForm_Load(this, EventArgs.Empty);
}
}
}
@@ -1,21 +1,28 @@
using TBF.Rig.Configs.NameOnly;
using TBF.Rig.Generic;
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
{
public abstract class SmartComponentBase : ComponentBase, ISmartTestMethod
{
private ITestMethodCfg cfg;
public abstract void MeterCommMilestone(int iItem, bool bValue);
public abstract bool IsMeterCommMilestone(int iItem);
public ITestMethodCfg TestMethodCfg { get => cfg; }
public SmartComponentBase()
: base()
{
cfg = null;
}
public SmartComponentBase(IComponentCfg cfg)
: base(cfg)
{
this.cfg = cfg as ITestMethodCfg;
}
}
}
@@ -0,0 +1,16 @@
using Common;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common
{
public interface ICommonRegReader : IRegReader
{
new string Name { get; }
new DebugMode DebugLevel { get; set; }
public string SerialNr { get; set; }
new double BeginWMState { get; set; } /// Test begin state of the water meter
new double EndWMState { get; set; } /// Test end state of the water meter
}
}
@@ -5,11 +5,14 @@ using TBF.Rig.RegisterReaders.CommonRR;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common
{
public interface ISmartReader : IRegReader
public interface ISmartReader : ICommonRegReader
{
new string Name { get; }
new DebugMode DebugLevel { get; set; }
public string SerialNr { get; }
new string SerialNr { get; set; }
new double BeginWMState { get; set; } /// Test begin state of the water meter
new double EndWMState { get; set; } /// Test end state of the water meter
public string CommInterface { get; }
public int RfidComPortNr { get; }
@@ -0,0 +1,30 @@
using System;
using System.ComponentModel;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
public static class EnumExtensions
{
public static bool TryParseByDescription<TEnum>(string description, out TEnum result)
where TEnum : struct, Enum
{
foreach (var field in typeof(TEnum).GetFields())
{
var attribute = Attribute.GetCustomAttribute(field,
typeof(DescriptionAttribute)) as DescriptionAttribute;
if ((attribute != null && attribute.Description == description) ||
field.Name == description)
{
result = (TEnum)field.GetValue(null);
return true;
}
}
result = default;
return false;
}
}
}
@@ -1,19 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Common;
using Config.Entities;
using log4net;
using Results.Entities;
using TBF.Rig.Generic;
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
using TBF.Rig.RegisterReaders.PoseidonReader;
using TBF.Rig.RegisterReaders.PoseidonReader.communication;
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
using TBF.Rig.Sequences;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
using TBF.Rig.TestMethods.SmartTest;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using CheckBoxImage = TBF.Boxes.CheckBoxImage;
using Factory = TBF.Rig.RegisterReaders.iPerlReaderUNI.Factory;
using PoseidonReader = TBF.Rig.RegisterReaders.PoseidonCmdStartStop.PoseidonReader;
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
@@ -32,6 +41,16 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
private IList<Test> tests;
private IList<ITestParams> multiTestParams;
private SmartCommunicationForm _parentFrom;
static IList<Thread> workerThreads;
static bool stopWorkerThreads;
static int currentActivityStep;
static int currentGroup;
/// form -> worker thread (0 = none)
static int lastGroup;
static int completedCommCount;
public string TypeIdentificatorName()
@@ -56,12 +75,122 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
public IList<ISmartReader> iperlHeads { get => ParentFrom.Heads;}
private Label activityLabel { get => ParentFrom?.ActivityLabel;}
private Label[] labels { get => ParentFrom?.Labels; }
private PictureBox[] counters{get => ParentFrom?.Counters;}
private TextBox[] messages{get => ParentFrom?.Messages;}
private CheckBoxImage[] checkBoxes{get => ParentFrom?.CheckBoxes;}
private int[] ckbIndex{get => ParentFrom?.CkbIndex;}
private bool[] ckbState{get => ParentFrom?.CkbState;}
public void Worker(object threadData)
{
throw new NotImplementedException();
int threadID = (threadData as Boxes.IntBox)?.Val ?? -1;
int activityStep = 0; /// activity step > 0 in case multiTestParams are used
for (int iMultiTestParamsItem = 0; iMultiTestParamsItem < MultiTestParams.Count; iMultiTestParamsItem++)
{
Test currentTest = Tests[iMultiTestParamsItem];
ITestParams currentTestParams = MultiTestParams[iMultiTestParamsItem];
string currentActivity = currentTestParams.Activity; /// Current activity
TBF.UiBridge.TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 10, 0, 140, 0, 0, 0 });
TBF.UiBridge.Bridge.OnTestProgress(null,
new TBF.UiBridge.TestProgressEventArgs(currentTest, Progress.JustStarted));
if (threadID == 0)
{
StartDataStreamProcessingForActiveMeters(iMultiTestParamsItem);
/// A new activity starts - information into RFID data log
rfidDataLogger.InfoFormat("");
rfidDataLogger.WarnFormat("Activity = {0}", currentActivity);
rfidDataLogger.InfoFormat("");
}
for (int group = 1; group <= lastGroup; group++)
{
/// Synchronize with QuidoRS and other threads
while (((group != currentGroup) || (activityStep != currentActivityStep)) &&
!GetStopWorkerThreads())
{
Thread.Sleep(50);
}
if (GetStopWorkerThreads()) break;
// #if TURA_SPECIAL
int threadIx = threadID; /// Just one thread for TURA_SPECIAL
// #else
// for (int threadIx = threadID; threadIx < threadID + 4; threadIx += Cfg.NrThreads)
// #endif
{
bool wmFound = false;
for (int wmNr0 = 0; wmNr0 < iperlHeads.Count; wmNr0++)
{
//TODO BUMI doplnit if podomienky - last grop je teraz 1 ak existuju readre
if(iperlHeads[wmNr0] is SmartReader ihead)
// if ((ihead.Group == group) && (threadIx < muxBrdOrGroup14Nrs.Count) &&
// (ihead.MuxBoardNrOrGroup14 == muxBrdOrGroup14Nrs[threadIx]))
{
wmFound = true;
WaterMeter wm = null;
if (ProcessData.BatchRslts.Batch.WaterMeters != null)
{
foreach (var w in ProcessData.BatchRslts.Batch.WaterMeters)
{
if (w.WMPosition == wmNr0 + 1)
{
wm = w;
break;
}
}
}
//Do worker activity
CommErr error = CommErr.None;
string resultStr = string.Empty;
WorkerActivity(currentActivity, ihead, wm, currentTest,
wmNr0, ref error, ref resultStr, ckbState, threadID, currentActivityStep);
ProcessResultOfWorkerActivity(iMultiTestParamsItem, currentActivity,
currentGroup, ihead, wm, wmNr0, error, resultStr, ckbState, threadID);
break;
}
TBF.UiBridge.Bridge.OnTestProgress(null,
new TBF.UiBridge.TestProgressEventArgs(Tests[iMultiTestParamsItem],
Progress.FlowSetting));
}
if (!wmFound)
{
SmartCommunicationForm.OnCommCompleted(null,
new CommCompletedEventArgs(threadID, -1, null, null, string.Empty,
CommErr.None)); /// Send negative wmNr
}
if (GetStopWorkerThreads()) break;
}
if (GetStopWorkerThreads()) break;
} /// for (int group
TBF.UiBridge.Bridge.OnTestProgress(null,
new TBF.UiBridge.TestProgressEventArgs(Tests[iMultiTestParamsItem], Progress.Completed));
activityStep++;
if (GetStopWorkerThreads()) break;
}
}
public bool WorkerActivity(string currentActivity, ISmartReader iHead, WaterMeter wm, Test currentTest, int wmNr0,
@@ -78,17 +207,17 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
public void StopWorkerThreads(bool bStopAllThreads)
{
throw new NotImplementedException();
stopWorkerThreads = bStopAllThreads;
}
public bool GetStopWorkerThreads()
{
throw new NotImplementedException();
return stopWorkerThreads;
}
public IList<Thread> GetAllThreads()
{
throw new NotImplementedException();
return workerThreads;
}
public ICorrections GetNewCorrection()
@@ -100,37 +229,229 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
throw new NotImplementedException();
}
public ContextMenu GetContextMenu()
{
throw new NotImplementedException();
}
public void PrepareForTestsActivities( int waterMeterPositions0)
{
throw new NotImplementedException();
StartTime = DateTime.Now;
StartTimeSec = StateMachine.Time;
///
/// Prepare worker threads, 'rfidPortNrs', 'lastGroup', etc..
///
currentActivityStep = 0;
currentGroup = 0;
completedCommCount = 0;
stopWorkerThreads = false;
lastGroup = 0;
if (iperlHeads != null)
{
foreach (var iSmartReader in iperlHeads)
{
try
{
if (iSmartReader is SmartReader reader){
if (reader != null ) lastGroup = 1;
}
}
catch (Exception E)
{
log.ErrorFormat("PrepareForTestsActivities: {0}", E.Message);
}
}
}
workerThreads = new List<Thread>();
if (Cfg != null)
{
for (int i = 0; i < Cfg.NrThreads; i++)
{
Thread thread = new Thread(Worker);
thread.CurrentCulture = CultureInfo.CurrentCulture;
thread.CurrentUICulture = CultureInfo.CurrentUICulture;
workerThreads.Add(thread);
}
}
}
public void Load(Label[] labels, PictureBox[] counters, TextBox[] messages, CheckBoxImage[] checkBoxes, int[] ckbIndex,
bool[] ckbState, IList<ISmartReader> iperlHeads, int textBoxesCount, bool checkBoxesEditMode)
{
throw new NotImplementedException();
if (iperlHeads == null)
{
for (int i = 0; i < textBoxesCount; i++)
{
checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = true;
messages[i].Text = "---";
}
return;
}
///
/// Set checkbox states accroding to iPerlHeads[i].Disabled states
///
for (int i = 0; i < textBoxesCount; i++)
{
labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = true;
ISmartReader iperlHead = iperlHeads[i];
if (!checkBoxesEditMode && (iperlHead == null || iperlHead.Disabled))
{
/// iPerl position i+1 is disabled
checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = false;
counters[i].BackColor = iPerlCommunicationConstants.DisabledColor;
messages[i].Text = "Strings.Head_was_disabled_by_the_user";
}
else
{
/// iPerl position i+1 is enabled
checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = true;
messages[i].Text = "---";
}
}
}
public int GetHeadsCount()
{
throw new NotImplementedException();
return ParentFrom?.Heads?.Count() ?? 0;
}
public void StartDataStreamProcessingForActiveMeters(int iMultiTestParamsItem)
{
throw new NotImplementedException();
/// Check whether previous activity was 'Set test mode A0' or 'A4'
if (iMultiTestParamsItem > 0 &&
MultiTestParams[iMultiTestParamsItem - 1].Activity.ToLower()
.Contains(iPerlCommunicationConstants.SetTestModeStr.ToLower()) &&
!MultiTestParams[iMultiTestParamsItem - 1].Activity.Contains("80"))
{
/// Start processing of opto-datastreams from all iPERL-s
int count = 0;
for (int wmNr0 = 0; wmNr0 < iperlHeads.Count; wmNr0++)
{
WaterMeter wm = (ProcessData.BatchRslts.Batch.WaterMeters != null &&
ProcessData.BatchRslts.Batch.WaterMeters.Count > wmNr0)
? ProcessData.BatchRslts.Batch.WaterMeters[wmNr0]
: null;
ISmartReader ihead = iperlHeads[wmNr0];
if (ihead != null && wm != null && !wm.Disabled)
{
lock (ihead)
{
ihead.StartDataStreamProcessing();
count++;
}
}
}
log.WarnFormat("End of activity '{0}', StartDataStreamProcessing() of {1} heads was called.",
MultiTestParams[iMultiTestParamsItem - 1].Activity, count);
}
}
public void DoOnCommCompleted(object sender, CommCompletedEventArgs data, IList<int> waterMeterPositions0)
{
throw new NotImplementedException();
try
{
///
/// Update the text message
///
if (data.WMNr0 >= 0) messages[data.WMNr0].Text = data.CommMessage;
///
/// Update head active/inactive switch
///
if (data.WMNr0 >= 0 && data.CommErr == CommErr.HeadDisabledByUser)
{
/// iPerl head was disabled by the user
ckbState[data.WMNr0] = false;
checkBoxes[data.WMNr0].Checked = false;
checkBoxes[data.WMNr0].Enabled = false;
if (data.Ihead != null) data.Ihead.Disabled = true;
if (data.Wm != null) data.Wm.Disabled = true;
}
else if (data.WMNr0 >= 0 && data.CommErr == CommErr.None)
{
/// One RFID communication successful => iPerl cannot be disabled by the user anymore
ckbState[data.WMNr0] = true;
checkBoxes[data.WMNr0].Checked = true;
checkBoxes[data.WMNr0].Enabled = false;
}
///
/// Update opto-communication indication
///
for (int i = 0; i < iperlHeads.Count; i++)
{
if (iperlHeads[i] == null || iperlHeads[i].Disabled)
{
counters[i].BackColor = iPerlCommunicationConstants.DisabledColor;
}
else
{
if (iperlHeads[i] is SmartReader iperlHead)
{
OptoHeadState checkFlowDirection =
((iperlHead == null) ? OptoHeadState.Disabled : iperlHead.CheckFlowDirection());
switch (checkFlowDirection)
{
case OptoHeadState.OptoAndDirOK:
counters[i].BackColor = iPerlCommunicationConstants.OptoAndDirOKColor;
break;
case OptoHeadState.DirNok:
counters[i].BackColor = iPerlCommunicationConstants.DirNokColor;
break;
default:
case OptoHeadState.OptoNok:
counters[i].BackColor = iPerlCommunicationConstants.OptoNokColor;
break;
}
}
}
}
#if !TURA_SPECIAL
///
/// Branch
///
lock (this)
{
if (++completedCommCount < 4) return;
completedCommCount = 0;
}
#endif
if (currentGroup < lastGroup)
{
/// Go to the next step / next group
currentGroup++;
}
else if (currentActivityStep + 1 < MultiTestParams.Count)
{
currentGroup = 0;
currentActivityStep++;
activityLabel.Text = MultiTestParams[currentActivityStep].Activity;
currentGroup++;
}
else
{
/// Wait until all threads are finished
workerThreads[data.ThreadId].Join(2000);
ParentFrom.NormalClose();
}
}
catch (Exception e)
{
log.ErrorFormat("DoOnCommCompleted({0}) failed: {1}", data, e.Message);
log.FatalFormat("StackTrace : {0}{1}", Environment.NewLine, e.StackTrace);
}
}
public void NormalClose(IList<int> waterMeterPositions0)
@@ -171,7 +492,129 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
this.cfg = cfg;
this.multiTestParams = multiTestParams;
}
//////////////////////////////////////////////////////////////
///
private MenuItem NewMenuItem(string text, string tag)
{
MenuItem menuItem = new MenuItem { Text = text, Tag = tag };
menuItem.Click += OnClick_Optical_Heads_Settings_Menu;
return menuItem;
}
private async void OnClick_Optical_Heads_Settings_Menu(object sender, EventArgs e)
{
// Validate sender
if (!(sender is MenuItem menuItem))
{
log?.Error("OnClick_Optical_Heads_Settings_Menu: sender is not a MenuItem");
return;
}
if (activityLabel != null)
activityLabel.Text = menuItem.Text;
List<Task> tasks = new List<Task>();
foreach (var iSmartReader in ProcessData.SmartHeadsUni)
{
if (!(iSmartReader is SmartReader iHead))
{
continue;//ignore different types of heads
}
int position = iHead.Position;
if (position < 0 || position >= checkBoxes.Length || position >= messages.Length)
{
continue; // Skip this head if position is out of range
}
if (!checkBoxes[position].Checked)
{
if (position < messages.Length) messages[position].Text = "";
continue;
}
messages[position].Text = $@"COM{iHead.RfidComPortNr}";
Application.DoEvents(); // Refresh UI
tasks.Add(Task.Run(async () =>
{
string result = await ProcessTask(iHead.RegPoseidonCfg, menuItem.Tag);
ParentFrom?.Invoke((Action)(() =>
{
messages[position].Text = result;
Application.DoEvents(); // Refresh UI
}));
}));
}
await Task.WhenAll(tasks);
}
public static bool TryParseByDescription(string description, out PoseidonImplHeadTestCtrl.Operations result)
{
foreach (PoseidonImplHeadTestCtrl.Operations op
in Enum.GetValues(typeof(PoseidonImplHeadTestCtrl.Operations)))
{
// step-by-step compare
var desc = ((Enum)op).ToDescription(); // uses extension above
// exact compare, you can use OrdinalIgnoreCase if you want
if (string.Equals(desc, description, StringComparison.Ordinal))
{
result = op;
return true;
}
}
result = PoseidonImplHeadTestCtrl.Operations.Empty;
return false;
}
private async Task<string> ProcessTask(IComponentCfg head, object tag)
{
string txt = "";
PoseidonImplHeadTestCtrl.Operations operation;
if (!TryParseByDescription((string)tag, out operation))
{
operation = PoseidonImplHeadTestCtrl.Operations.Empty;
}
if (head is PoseidonCfg poseidonCfg)
{
switch (operation)
{
case PoseidonImplHeadTestCtrl.Operations.ReadSerialNo:
txt = OpticalHeadTest.ReadRequest_SerialNo(poseidonCfg);
break;
case PoseidonImplHeadTestCtrl.Operations.SetTestModeOn:
txt = OpticalHeadTest.SetTestMode(poseidonCfg);
break;
case PoseidonImplHeadTestCtrl.Operations.SetTestModeOff:
txt = OpticalHeadTest.SetActiveMode(poseidonCfg);
break;
default:
txt = "-";
break;
}
}
return txt;
}
public ContextMenu GetContextMenu()
{
ContextMenu cm = new ContextMenu();
foreach (KeyValuePair<string, PoseidonImplHeadTestCtrl.Operations> itemsOperation in PoseidonImplHeadTestCtrl.ItemsOperations)
{
cm.MenuItems.Add(NewMenuItem(itemsOperation.Key, itemsOperation.Value.ToDescription()));
}
return cm;
}
}
}
+23
View File
@@ -1406,11 +1406,14 @@
<Compile Include="Rig\RegisterReaders\StandingStartStop\Factory.cs" />
<Compile Include="Rig\RegisterReaders\StandingStartStop\RRProcParams.cs" />
<Compile Include="Rig\RegValvePosition.cs" />
<Compile Include="Rig\Scales\MettlerToledo\ISerialPort.cs" />
<Compile Include="Rig\Scales\MettlerToledo\ScaleCfg.cs" />
<Compile Include="Rig\Scales\MettlerToledo\Scale.cs" />
<Compile Include="Rig\Scales\MettlerToledo\Factory.cs" />
<Compile Include="Rig\Scales\MettlerToledo\GetSerNumOp.cs" />
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOp.cs" />
<Compile Include="Rig\Scales\MettlerToledo\SerialPortDevice.cs" />
<Compile Include="Rig\Scales\MettlerToledo\SerialPortDeviceFake.cs" />
<Compile Include="Rig\Scales\MettlerToledo\SetUnitsOp.cs" />
<Compile Include="Rig\Scales\MettlerToledo\TaringOp.cs" />
<Compile Include="Rig\Scales\MettlerToledo\ZeroOp.cs" />
@@ -1643,6 +1646,21 @@
<Compile Include="Rig\TestMethods\StandingStartMassCollectionAdvance\Single\Component.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionAdvance\Single\Factory.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionAdvance\StandingStartMassCollectionAdvanceSeq.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\Compound\Component.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\Compound\Factory.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\HeatMeters\Component.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\HeatMeters\Factory.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\HeatMeters\TestMethodCfg.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\HeatMeters\TestMethodCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\HeatMeters\TestMethodCfgCtrl.designer.cs">
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\HeatMeters\TestParams.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\Single\Component.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\Single\Factory.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\StandingStartMassCollectionPoseidonSeq.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollection\Compound\Component.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollection\Compound\Factory.cs" />
<Compile Include="Rig\TestMethods\StandingStartMassCollection\HeatMeters\Component.cs" />
@@ -2046,8 +2064,10 @@
<Compile Include="Rig\Uni\RegValve\SetFlowOp.cs" />
<Compile Include="Rig\Uni\RegValve\SetRegValvePositionOp.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\AllCompletedEventArgs.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\common\ICommonRegReader.cs" />
<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\IPerlCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\PoseidonCorrections.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\SmartComponentBase.cs" />
@@ -3440,6 +3460,9 @@
<EmbeddedResource Include="Rig\TestMethods\StandingStartMassCollectionAdvance\HeatMeters\TestMethodCfgCtrl.resx">
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\TestMethods\StandingStartMassCollectionPoseidon\HeatMeters\TestMethodCfgCtrl.resx">
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\TestMethods\StandingStartMassCollection\HeatMeters\TestMethodCfgCtrl.resx">
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
@@ -0,0 +1,168 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Common;
using Config.Entities;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using TBF.Boxes;
using TBF.Rig;
using TBF.Rig.BuiltIn.Valve;
using TBF.Rig.ControlBoard.Uni;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
using TBF.Rig.Scales.MettlerToledo;
using Factory = TBF.Rig.Scales.MettlerToledo.Factory;
namespace TBFTests.Rig.Scales.MettlerToledo
{
[TestClass]
[TestSubject(typeof(ReadStableMassOp))]
public class ReadStableMassOpTest
{
[TestMethod]
public void Run_ReadStableMassOp()
{
//
var mockControlBoard = new Mock<TBF.Rig.ControlBoard.IControlBoard>();
mockControlBoard.Setup(v => v.Name).Returns("UniCB");
IList<IComponent> componentsBoard = new List<IComponent>() { mockControlBoard.Object};
StateMachine.InitializeBoardEtc_Fake(componentsBoard);
Factory factory = new Factory();
ScaleCfg cfg = new ScaleCfg("Scale0", factory);
cfg.Evaporation = "Evaporation0";
//
var mockValve = new Mock<IValve>();
mockValve.Setup(v => v.Name).Returns(cfg.DrainValve);
//
var mockEvaporation = new Mock<IEvaporation>();
mockEvaporation.Setup(v => v.Name).Returns(cfg.Evaporation);
//components
IComponent valveObject = mockValve.Object;
IComponent evaporationObject = mockEvaporation.Object;
IList<IComponent> components = new List<IComponent>() { valveObject, mockControlBoard.Object, evaporationObject };
StateMachine.InitializeBoardEtc_Fake(components);
ValveCfg valveCfg = new ValveCfg(new ValveFactory());
var valveFactory = new ValveFactory();
IComponent iComponent = valveFactory.GetComponent(valveCfg,components);
SerialPortDeviceFake serialPort = new SerialPortDeviceFake();
Scale scale = factory.GetComponent(cfg,null, serialPort) as Scale;
scale.DebugLevel = DebugMode.Normal;
scale.Initialize();
DoubleBox finalMass = new DoubleBox();
ReadStableMassOp readStableMassOp = new ReadStableMassOp(scale, ref finalMass, 2, MassMethod.Scale, 4, 0.05);
//////////////////////////////////
/// Start
readStableMassOp.Start();
/// Run
bool stopLoop = false;
while(!stopLoop)
{
Event run = readStableMassOp.Run();
if (run == Event.Abort || run == Event.ScaleDone)
{
stopLoop = true;
break;
}
if (StateMachine.Time >= 2 && StateMachine.Time < 3) // delay
{
//must be send command to stabilisate mass
Assert.IsTrue(scale.Activity == Activity.RunningOperation);
Assert.IsTrue(serialPort.IsOpen);
Assert.IsTrue(serialPort.LastWrite.Contains("S\r\n"));
Assert.IsTrue(string.IsNullOrEmpty(serialPort.LastRead));
}
//time gap between measurements - 60 sec
if (StateMachine.Time == 61) //valid measurement
{
//FIRST measurement
Assert.IsTrue(scale.Activity == Activity.RunningOperation);
//try simulate immediate measurement
scale.Activity = Activity.ImmediateMeasurement;
scale.RunDeviceBefore();
Assert.IsTrue(scale.Activity == Activity.Idle);
Assert.IsTrue(scale.MsrmntState == MsrmntState.Valid);
Assert.IsTrue(scale.Mass-0.1 < 170.725 && scale.Mass+0.1 > 170.724); //value from fake serial port
}
if (StateMachine.Time == 62) //valid measurement
{
//SECOND measurement - forced answer
scale.Activity = Activity.ImmediateMeasurement;
serialPort.ForceReturnAnswer("S S 0.000 kg");
scale.RunDeviceBefore();
Assert.IsTrue(scale.Activity == Activity.Idle);
Assert.IsTrue(scale.MsrmntState == MsrmntState.Valid);
Assert.IsTrue(scale.Mass-0.1 < 0 && scale.Mass+0.1 > 0);
}
////////// ERROR CASES
if (StateMachine.Time >= 63 && StateMachine.Time < 65) // 2x invalid parameter S_I
{
//FAILED in customer measurement - forced answer
scale.Activity = Activity.ImmediateMeasurement;
serialPort.ForceReturnAnswer("S I"); //not ready scale
scale.RunDeviceBefore();
Assert.IsTrue(scale.MsrmntState == MsrmntState.Failed);
Assert.IsTrue(scale.Activity == Activity.Idle);
}
// SET Correct answer
if (StateMachine.Time >= 66 && StateMachine.Time < 70) //valid parametrs - IF 4 times valid measurement finish and calculate average final mass
{
//FAILED in customer measurement - forced answer
scale.Activity = Activity.ImmediateMeasurement;
serialPort.ForceReturnAnswer("S S 120.56 kg"); //not ready scale
scale.RunDeviceBefore();
Assert.IsTrue(scale.MsrmntState == MsrmntState.Valid);
Assert.IsTrue(scale.Activity == Activity.Idle);
}
////////// ~ ERROR CASES
if (StateMachine.Time >= 70)
{
Assert.Fail( "Timeout");
return;
}
Thread.Sleep(10);
StateMachine.Time += 1;
}
/// Stop
readStableMassOp.Stop();
Assert.IsTrue(scale.Activity == Activity.Idle);
Assert.IsTrue(scale.MsrmntState == MsrmntState.Valid);
Assert.IsTrue(finalMass.Val-0.1 < 60.28 && finalMass.Val+0.1 > 60.28);
//////////////////////////////////////
}
}
}
@@ -0,0 +1,41 @@
using Common;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations;
namespace TBFTests.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
{
[TestClass]
[TestSubject(typeof(PoseidonCorrections))]
public class PoseidonCorrectionsTest
{
[TestMethod]
public void TryParseByDescription_test()
{
PoseidonImplHeadTestCtrl.Operations testOp = PoseidonImplHeadTestCtrl.Operations.ReadSerialNo;
ValidateOperationParsing(testOp.ToDescription());
testOp = PoseidonImplHeadTestCtrl.Operations.SetTestModeOn;
ValidateOperationParsing(testOp.ToDescription());
testOp = PoseidonImplHeadTestCtrl.Operations.SetTestModeOff;
ValidateOperationParsing(testOp.ToDescription());
//negative test
ValidateOperationParsing("khvcdh jkbhvf", false);
}
private static void ValidateOperationParsing(string tag, bool expectedResult = true)
{
PoseidonImplHeadTestCtrl.Operations operation;
if (!PoseidonCorrections.TryParseByDescription((string)tag, out operation))
{
Assert.IsFalse(expectedResult);
}
else
{
Assert.IsTrue(operation.ToDescription() == tag);
}
}
}
}
+6
View File
@@ -106,6 +106,8 @@
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTest.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReaderTest.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonReader\UniHeadTestCtrlTest.cs" />
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOpTest.cs" />
<Compile Include="Rig\Uni\SharedDialogs\SmartMetersCommunication\implementations\PoseidonCorrectionsTest.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
@@ -124,6 +126,10 @@
<Project>{9d0dcc88-dc81-47eb-9fdd-4c3907871bfb}</Project>
<Name>Results</Name>
</ProjectReference>
<ProjectReference Include="..\SchematicDrawing\SchematicDrawing.csproj">
<Project>{0f79ca69-9dbc-41f3-a6fc-5a2937365343}</Project>
<Name>SchematicDrawing</Name>
</ProjectReference>
<ProjectReference Include="..\TBF\TBF.csproj">
<Project>{8648FD92-CDA1-4C3A-B5F9-FE547CE1FA48}</Project>
<Name>TBF</Name>