- Introduce `OptoComPortNr` and `HeadComPortNr` properties in `GenesisHead`. - Update `SetupGenesisMeter` to use new COM port configurations. - Add reference to `Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig`.
657 lines
20 KiB
C#
657 lines
20 KiB
C#
using Config.Entities;
|
|
using log4net;
|
|
///
|
|
/// Copyright (c) 2015-2018 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using TBF.Rig.Generic;
|
|
using TBF.Rig.GenericDevices;
|
|
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
|
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
|
|
using Xylem.Common.Metrology.Measurements;
|
|
using Xylem.Common.Metrology.Measurements.Consts;
|
|
using Common;
|
|
using System.IO.Ports;
|
|
|
|
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
|
{
|
|
public static class GenesisHeadBatch
|
|
{
|
|
public static Dictionary<string, List<MeasurementResults>> MeterIdDetailResults = new Dictionary<string, List<MeasurementResults>>();
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(GenesisHeadBatch));
|
|
public static readonly Lazy<MeterBatch> BatchHolder = new Lazy<MeterBatch>(() =>
|
|
{
|
|
return new MeterBatch();
|
|
});
|
|
|
|
internal static bool Start(IRegReader[] registerReaders, string[] lastSNTexts)
|
|
{
|
|
try
|
|
{
|
|
MeterIdDetailResults = new Dictionary<string, List<MeasurementResults>>();
|
|
int index = 0;
|
|
var ret = false;
|
|
foreach (var rr in registerReaders)
|
|
{
|
|
if (rr is TestMethods.GenesisCommunication.GenesisHead.GenesisHead)
|
|
{
|
|
if (!string.IsNullOrEmpty(lastSNTexts[index]))
|
|
{
|
|
var myGenesis = ((TestMethods.GenesisCommunication.GenesisHead.GenesisHead)rr).SetUp();
|
|
myGenesis.SerialNumber = lastSNTexts[index];
|
|
ret = true;
|
|
}
|
|
}
|
|
index = index + 1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Fatal(ex.Message, ex);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// This component = instance of this class is a placeholder for a combined main watermeter
|
|
/// </summary>
|
|
public class GenesisHead : ComponentBase, IDevice, GenericDevices./*IRegisterReader*/IRegReader, IOperation
|
|
{
|
|
public List<MeasurementResults> DetailedResults { get; set; }
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(GenesisHead));
|
|
public override string ToString() { return string.Format("Genesis({0})", Cfg.ToString(1)); }
|
|
|
|
public RegisterReaderType RegisterReaderType { get { return RegisterReaderType.DataStream; } }
|
|
|
|
private readonly GenesisHeadCfg genesisHeadCfg;
|
|
public int SlotNr { get { return genesisHeadCfg.SlotNr; } }
|
|
public int OptoComPortNr { get { return genesisHeadCfg.OptoComPortNr; } }
|
|
public int HeadComPortNr { get { return genesisHeadCfg.HeadComPortNr; } }
|
|
public double PulsesPerLtr { get { return 1000.0; } }
|
|
public double LtrsPerPulse { get { return 1 / PulsesPerLtr; } }
|
|
public string QuantityUnits { get; set; }
|
|
public int Position { get; }//...MF
|
|
double IRegReader.PulsesPerLtr { get; set; }
|
|
|
|
// Adding the missing static method to resolve the error. ...MF
|
|
public static void ResetStaticProperties()
|
|
{
|
|
// Add logic to reset static properties here, if applicable.
|
|
// If no static properties exist, this method can remain empty.
|
|
}
|
|
|
|
#if ORACLE_DB
|
|
public int WMType_ID { get { return iperlHeadCfg.ProcParams.WMType_ID; } } /// Required by Oracle DB
|
|
public int WMType_Rev { get { return iperlHeadCfg.ProcParams.WMType_Rev; } } /// Required by Oracle DB
|
|
#endif
|
|
public float CalibTarget { get { return (ushort)genesisHeadCfg.ProcParams.CalibTarget; } }
|
|
public ushort FactorLimitLo { get { return (ushort)genesisHeadCfg.ProcParams.FactorLimitLo; } }
|
|
public ushort FactorLimitHi { get { return (ushort)genesisHeadCfg.ProcParams.FactorLimitHi; } }
|
|
|
|
/// Properties set by the Begin and the End form
|
|
//todo rd implement
|
|
public string SerialNr;
|
|
|
|
|
|
public string EndState
|
|
{
|
|
get { return endState; }
|
|
set { endState = value; }
|
|
}
|
|
|
|
private string endState;
|
|
|
|
public string BeginState
|
|
{
|
|
get { return beginState; }
|
|
set { beginState = value; }
|
|
}
|
|
|
|
private string beginState;
|
|
|
|
public bool Disabled
|
|
{
|
|
get { return disabled; }
|
|
set { disabled = value; }
|
|
}
|
|
|
|
private bool disabled;
|
|
|
|
public bool CommFailed
|
|
{
|
|
get { return commFailed; }
|
|
set { commFailed = value; }
|
|
}
|
|
|
|
private bool commFailed;
|
|
|
|
public int ResultCode
|
|
{
|
|
get { return resultCode; }
|
|
}
|
|
|
|
private int resultCode;
|
|
|
|
|
|
/// <summary> ConfigStruct of the water meter obtained or updated by iPerlCommunication </summary>
|
|
public ConfigStruct ConfigStruct
|
|
{
|
|
get { return configStruct; }
|
|
set { configStruct = value; }
|
|
}
|
|
|
|
private ConfigStruct configStruct;
|
|
|
|
/// <summary> CalibrationStruct of the water meter obtained or updated by iPerlCommunication </summary>
|
|
public CalibrationStruct CalibrationStruct
|
|
{
|
|
get { return calibrationStruct; }
|
|
set { calibrationStruct = value; }
|
|
}
|
|
|
|
private CalibrationStruct calibrationStruct;
|
|
|
|
public ushort OrigCalibFactor;
|
|
public ushort CalibFactor { get { return (CalibrationStruct != null) ? CalibrationStruct.Calibration : (ushort)0; } }
|
|
|
|
public double Q2ErrWOCorrection;
|
|
public bool Q2CorrectionDone;
|
|
public double Q2Correction;
|
|
public int Q2CorrRFlow;
|
|
public int Q2CorrLFlow;
|
|
|
|
public double Diff2Hz8Hz;
|
|
public bool Hz2CorrectionDone;
|
|
public int Hz2Correction;
|
|
|
|
public string FWVersion { get { return (CalibrationStruct != null) ? CalibrationStruct.FWVersionStr() : string.Empty; } }
|
|
|
|
|
|
/// <summary> Result of the last test used to calculate Q2 correction factors, etc </summary>
|
|
public Results.Entities.MeterTestRslt LastTestResult2;
|
|
public Results.Entities.MeterTestRslt LastTestResult;
|
|
public double NominalTestFlowLph; /// in liter per hour
|
|
|
|
|
|
///
|
|
/// Required for IRegisterReader interface
|
|
///
|
|
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 WMTestTime { get { return wmTestTime; } }
|
|
|
|
private double beginWMState;
|
|
private double endWMState;
|
|
private double wmVolume;
|
|
private int wmPulses;
|
|
private int wmRefPulses;
|
|
private double wmTestTime;
|
|
|
|
|
|
/// <summary> Name set by the test, to be used as a part of the opto-data log file name </summary>
|
|
public string TestName;
|
|
|
|
/// <summary> Name set by the test, to be used as a part of the opto-data log file name </summary>
|
|
public string BenchName;
|
|
|
|
///
|
|
/// Volume of water from the opto telegram
|
|
///
|
|
private Int64 lastVolumeRaw; /// Last read raw volume
|
|
private double volumeLtr; ///
|
|
private double volumeLtr0;
|
|
|
|
|
|
///
|
|
/// Timestamp from the opto telegram
|
|
///
|
|
private double timestampSec;
|
|
private double timestampSec0;
|
|
|
|
public bool NoSamples { get { return (timestampSecEnd - timestampSecStart) < float.Epsilon; } }
|
|
public double TimestampSecStart { get { return timestampSecStart; } }
|
|
public double TimestampSecEnd { get { return timestampSecEnd; } }
|
|
|
|
private double timestampSecStart;
|
|
private double timestampSecEnd;
|
|
|
|
public GenesisHead()
|
|
{
|
|
}
|
|
|
|
public GenesisHead(Generic.IComponentCfg cfg)
|
|
: base(cfg)
|
|
{
|
|
ClearData();
|
|
|
|
genesisHeadCfg = cfg as GenesisHeadCfg;
|
|
|
|
log.Debug(this.ToString());
|
|
}
|
|
|
|
private GenesisMeter myGenesis = null;
|
|
|
|
|
|
|
|
|
|
|
|
public GenesisMeter SetUp()
|
|
{
|
|
try
|
|
{
|
|
Log("Call SetUp()");
|
|
if (myGenesis != null)
|
|
{
|
|
myGenesis.DisposeMeter();
|
|
}
|
|
//add for gen
|
|
|
|
myGenesis = new GenesisMeter();
|
|
//myGenesis.SetupFromConfigFile(SlotNr);
|
|
//myGenesis.SetLogger(); - private, but called into basic constructor!
|
|
myGenesis.SetupGenesisMeter(
|
|
SlotNr,
|
|
new Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.PortConfig()
|
|
{
|
|
Type = "Xylem.Common.Hardware.Interfaces.Ports.SerialPorts.IrdaSerialPort",
|
|
PortName =$"COM{HeadComPortNr}"
|
|
},
|
|
new Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.PortConfig()
|
|
{
|
|
Type = "",
|
|
PortName = $"COM{OptoComPortNr}"
|
|
}
|
|
);
|
|
|
|
Log("Add Meter to batch");
|
|
GenesisHeadBatch.BatchHolder.Value.AddMeter(myGenesis);
|
|
Log("Log Raw Data");
|
|
myGenesis.LogRawData(true);
|
|
return myGenesis;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (myGenesis != null)
|
|
{
|
|
Log(e.Message);
|
|
}
|
|
throw e;
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear data related to a specific water meter
|
|
/// </summary>
|
|
public void ClearData()
|
|
{
|
|
DetailedResults = new List<MeasurementResults>();
|
|
resultCode = 0;
|
|
|
|
disabled = false;
|
|
commFailed = false;
|
|
endState = string.Empty;
|
|
beginState = string.Empty;
|
|
|
|
configStruct = null;
|
|
calibrationStruct = null;
|
|
|
|
LastTestResult = null;
|
|
NominalTestFlowLph = 0;
|
|
|
|
OrigCalibFactor = 0;
|
|
Q2ErrWOCorrection = 0;
|
|
Q2CorrectionDone = false;
|
|
Q2CorrRFlow = 0;
|
|
}
|
|
|
|
public override void Initialize()
|
|
{
|
|
ClearData();
|
|
|
|
if (DebugLevel == DebugMode.Normal)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
public void RunDeviceBefore()
|
|
{
|
|
|
|
|
|
////todo: RD- Login??
|
|
//if (DebugLevel == DebugMode.Normal)
|
|
//{
|
|
|
|
|
|
// if (myGenesis != null)
|
|
// {
|
|
// Log("TBF RunDeviceBefore");
|
|
|
|
// }
|
|
// else
|
|
// {
|
|
// //throw new Exception("No meter was bound!");
|
|
// }
|
|
//}
|
|
//else if (DebugLevel == DebugMode.FailureDuringOperation)
|
|
//{
|
|
//}
|
|
}
|
|
|
|
public void RunDeviceAfter() { }
|
|
|
|
public void StopDevice()
|
|
{
|
|
try
|
|
{
|
|
|
|
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
|
{
|
|
myGenesis.DisposeMeter();
|
|
|
|
GenesisHeadBatch.BatchHolder.Value.RemoveMeter(myGenesis);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
public void StopDevice2() { }
|
|
|
|
/// <summary>
|
|
/// Events: Event.ReadRegisterDone, Event.Error
|
|
/// </summary>
|
|
/// <returns>ReadWaterMeter instance reference casted to IOperaton</returns>
|
|
public IOperation ReadRegisterOp()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear data/counters related to a specific tests
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
resultCode = 0;
|
|
|
|
sampleNr = 0;
|
|
|
|
volumeLtr = 0;
|
|
volumeLtr0 = 0;
|
|
timestampSec = 0;
|
|
timestampSec0 = 0;
|
|
|
|
ReadPulses();
|
|
}
|
|
|
|
public void TestCompleted()
|
|
{
|
|
/// TODO: Implement
|
|
}
|
|
|
|
private int sampleNr; /// This is to determine when the test start sample should be taken
|
|
|
|
|
|
private bool StoreStartPackage = false;
|
|
private bool StoreEndPackage = false;
|
|
private bool Enable = false;
|
|
public bool IsCalibration = false;
|
|
/// <summary>Start this operation</summary>
|
|
public void Start()
|
|
{
|
|
|
|
|
|
}
|
|
public void StartRead(string TestName, int batchNr, int repetitionNr)
|
|
{
|
|
StoreStartPackage = false;
|
|
StoreEndPackage = false;
|
|
//Start mesurement
|
|
if (DebugLevel == DebugMode.Normal)
|
|
{
|
|
if (myGenesis != null)
|
|
{
|
|
IsCalibration = false;
|
|
Log($"TBF Start Measurement {TestName}");
|
|
myGenesis.CurrentActionText = $"Batch{batchNr}_Rep{repetitionNr}";
|
|
|
|
|
|
if (TestName.ToLower().Contains("calib"))
|
|
{
|
|
IsCalibration = true;
|
|
//myGenesis.Login();
|
|
myGenesis.StartCalibration();
|
|
}
|
|
else if (TestName.ToLower().Contains("login"))
|
|
{
|
|
//myGenesis.Login();
|
|
|
|
myGenesis.InitMeasurement();
|
|
}
|
|
else
|
|
{
|
|
DetailedResults = new List<MeasurementResults>();
|
|
|
|
myGenesis.StartMeasurement();
|
|
}
|
|
|
|
StoreStartPackage = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Log(string text)
|
|
{
|
|
log.Debug(text);
|
|
if (DebugLevel == DebugMode.Normal)
|
|
{
|
|
if (myGenesis != null)
|
|
{
|
|
myGenesis.WriteLog(text);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>Run this operation</summary>
|
|
/// <returns>eventDone</returns>
|
|
public Event Run()
|
|
{
|
|
if (DebugLevel == DebugMode.Normal)
|
|
{
|
|
if (myGenesis != null)
|
|
{
|
|
try
|
|
{
|
|
//var results = myGenesis.GetIntermediateMeasurementResult();
|
|
//readOutResults(results);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return Event.ReadRegisterDone;
|
|
}
|
|
public double RefVolume = 0.0;
|
|
|
|
public void Stop()
|
|
{
|
|
//Stop(null);
|
|
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
|
{
|
|
if (IsCalibration)
|
|
{
|
|
myGenesis.StopCalibration();
|
|
}
|
|
else
|
|
{
|
|
myGenesis.StopMeasurement();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Stop this operation</summary>
|
|
public void Stop(Double? testTimeS = null, double? refVol = null)
|
|
{
|
|
|
|
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
|
{
|
|
Log($"TBF Stop Measurement {IsCalibration} {testTimeS} {refVol }");
|
|
if (IsCalibration)
|
|
{
|
|
//myGenesis.StopCalibration();
|
|
int retryCounter = 400;
|
|
while (myGenesis.GetCalibrationState() != MeasurementStates.IsCompleted)
|
|
{
|
|
if (retryCounter < 0)
|
|
{
|
|
break;
|
|
}
|
|
Thread.Sleep(10);
|
|
retryCounter = retryCounter - 1;
|
|
}
|
|
try
|
|
{
|
|
var results = myGenesis.GetMainMeasurementResult(refVol, testTimeS, false);
|
|
|
|
readOutResults(results, testTimeS);
|
|
if (refVol.HasValue && refVol.Value != 0.0)
|
|
{
|
|
|
|
|
|
myGenesis.BuildAndCheckCalibFactorsAllChannels(refVol.Value / 1000, testTimeS, Q2ErrWOCorrection);
|
|
myGenesis.SetCalibFactorsAllChannels(false);
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MarkAsError();
|
|
Log("Error while Stop Calib " + ex.Message);
|
|
if (ex.InnerException != null)
|
|
{
|
|
Log("Inner Error:" + ex.InnerException.Message);
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int retryCounter = 4000;
|
|
//myGenesis.StopMeasurement();
|
|
try
|
|
{
|
|
while (myGenesis.GetMeasurementState() != MeasurementStates.IsCompleted)
|
|
{
|
|
if (retryCounter < 0)
|
|
{
|
|
break;
|
|
}
|
|
Thread.Sleep(10);
|
|
retryCounter = retryCounter - 1;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (refVol.HasValue && testTimeS.HasValue)
|
|
{
|
|
Log("GetMainMeasurementResult V" + refVol.ToString() + " and S" + testTimeS.Value);
|
|
}
|
|
else
|
|
{
|
|
Log("GetMainMeasurementResult empty");
|
|
}
|
|
|
|
DetailedResults = myGenesis.GetAllMeasurementResults(refVol, testTimeS);
|
|
foreach (var item in DetailedResults)
|
|
{
|
|
Log("Detail Measurement Channel =" + item.Channel + "; CorrectedDutVolumeCm= " + item.CorrectedDutVolumeCm + "; DeviationDutToRefPer= " + item.DeviationDutToRefPer);
|
|
}
|
|
|
|
|
|
readOutResults(DetailedResults.First(), testTimeS);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MarkAsError();
|
|
Log("Error while Stop Measurement " + ex.Message);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MarkAsError();
|
|
Log("Error while GetMeasurementState " + ex.Message);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
StoreEndPackage = true;
|
|
|
|
}
|
|
}
|
|
|
|
private void readOutResults(MeasurementResults results, double? testTimeS)
|
|
{
|
|
volumeLtr = results.CorrectedDutVolumeCm * 1000;
|
|
timestampSec = results.DutStopRecord.GetTimeS();
|
|
if (testTimeS.HasValue)
|
|
{
|
|
wmTestTime = testTimeS.Value;
|
|
}
|
|
else
|
|
{
|
|
wmTestTime = results.DutTimeS;
|
|
}
|
|
|
|
wmVolume = results.CorrectedDutVolumeCm * 1000;
|
|
Log("DutFlowRateCmPh" + results.DutFlowRateCmPh.ToString());
|
|
Log("CorrectedDutVolumeCm=" + results.CorrectedDutVolumeCm.ToString());
|
|
Log("DutVolumeCm=" + results.DutVolumeCm.ToString());
|
|
ReadPulses();
|
|
}
|
|
|
|
private void MarkAsError()
|
|
{
|
|
volumeLtr = 0;
|
|
timestampSec = 0;
|
|
wmTestTime = 0;
|
|
wmVolume = 0;
|
|
ReadPulses();
|
|
}
|
|
|
|
private void ReadPulses()
|
|
{
|
|
beginWMState = volumeLtr0;
|
|
endWMState = volumeLtr;
|
|
wmPulses = (int)(wmVolume * (double)PulsesPerLtr + 0.5);
|
|
wmRefPulses = StateMachine.ControlBoardMain.RefPulses;//EtPulses(0);//...MF
|
|
}
|
|
|
|
private bool optoSerialPortParsingEnabled;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
}
|