common/Hardware/WaterMeter/Genesis/GenesisCore/_GenesisMeterMeasurement.cs
2026-04-23 17:50:07 +02:00

324 lines
13 KiB
C#

using ByteArrayStyle;
using System;
using System.Collections.Generic;
using System.Linq;
using Xylem.Common.CommonCore.Consts;
using Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.MeasurementRecords;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.Const;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Consts;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Metrology.Measurements;
using Xylem.Common.Metrology.Measurements.Consts;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
{
public partial class GenesisMeter
{
/// <summary>
/// List of ongoing measurements, base- and calibration-measurements
/// </summary>
private List<IMeasurement> _listOfIMeasurement = new List<IMeasurement>();
/// <summary>
/// All channels required to process
/// </summary>
public Boolean AllChannelsRequired = true;
/// <summary>
/// Quality watch mode can be used to decode intermediate records and check
/// for actual quality of the measurements.
/// </summary>
public Boolean QualityWatchMode;
/// <inheritdoc />
/// <summary>
/// Perpetration of Measurement
/// SampleRate 10 and Led mode Test
/// </summary>
public void InitMeasurement()
{
Logger.Info($"Slot:{Slot} - Init measurement");
PreMeasurement();
}
private void PreMeasurement()
{
if (!SkipPreparationForTestBench)
{
//SkipPreparationForTestBench = true;
//TODO set display unit
//TODO calculated overflow volume for display
WriteRegister<Byte>(Register.Genesisflow.SampleRate, 0x08, checkRegister: true);
WriteRegister(Register.Genesisflow.LedMode, (Byte)LedMode.FlowTestAndCalibData, checkRegister: true);
WriteRegister("GENESISFLOW_SealDisplay", 0, true, true);
try
{
var displayState = ReadRegister(Register.Genesisflow.TriggerIdle);
if (displayState == null)
{
displayState = ReadRegister(Register.Genesisflow.TriggerIdle);
if (displayState == null)
{
Logger.Info($"Slot:{Slot} - Not able to read display state");
return;
}
}
var displayStateString = ByteStyler.ToString(displayState);
if (displayStateString.Substring(0, 2) != "FF" || displayStateString.Substring(0, 5) == "FF-55")
{
WriteRegister(Register.Genesisflow.TriggerIdle, 0, true, true);
displayState = ReadRegister(Register.Genesisflow.TriggerIdle);
displayStateString = ByteStyler.ToString(displayState);
if (displayStateString != "00-00-00-00")
{
WriteRegister(Register.Genesisflow.TriggerActive, 1);
}
}
else
{
WriteLog($"meter not active because display code has an error on code:{displayStateString}");
}
}
catch (Exception)
{
// ignored
}
WriteRegister("GENESISFLOW_DisplayPow10", (new Byte[] { 0x00, 0x00, 0x00, 0xFA }).Reverse().ToArray());
//WriteRegister(Register.Genesisflow.StoreCalibration, 1);
//WriteRegister(Register.Genesisflow.StoreConfiguration, 1);
try
{
if (GetRegistersDic().Any(a => a.Key.RegisterName == "GENESISFLOW_DelayedLedOff"))
{
WriteRegister("GENESISFLOW_DelayedLedOff", 60 * 60 * 2, false);
}
}
catch (Exception)
{
}
}
else
{
WriteLog($"wait for measurement is starting");
}
ProcessStatus = ProcessState.WaitForMeasurement;
}
/// <inheritdoc />
public void StartMeasurement()
{
_listOfIMeasurement = new List<IMeasurement>
{
new BaseMeasurement(Slot, typeof(FlowTestRecord), IntermediateUpdateTimeS)
};
//add channels for calibration measurement
for (var i = 1; i <= MeterConfig.CalibChannels; i++)
{
_listOfIMeasurement.Add(new CalibrationMeasurement(Slot, typeof(CalibrationRecord), IntermediateUpdateTimeS, i));
}
foreach (var measurement in _listOfIMeasurement)
{
measurement.OnActionStateHasChanged += Measurement_ActionStateHasChanged;
}
Logger.Info($"Slot:{Slot} - Start measurement");
ProcessStatus = ProcessState.MeasurementIsActive;
_listOfIMeasurement.ForEach(m => m.MeasurementState = MeasurementStates.IsWaitingForStartData);
SyncStreamingBuffer(SyncMarkRecord.SyncStart);
}
/// <inheritdoc />
public void StopMeasurement()
{
Logger.Info($"Slot:{Slot} - Stop measurement");
ProcessStatus = ProcessState.MeasurementIsDone;
_listOfIMeasurement.ForEach(m => m.MeasurementState = MeasurementStates.IsWaitingForEndData);
SyncStreamingBuffer(SyncMarkRecord.SyncEnd);
}
/// <summary>
/// Testing the flow direction
/// </summary>
/// <returns></returns>
public Boolean CheckChannelFlowDirection()
{
Boolean? dirPositive = null;
foreach (var cali in _listOfIMeasurement.Where(m => m.GetType() == typeof(CalibrationRecord)))
{
var result = cali.GetIntermediateMeasurementResult();
var channelDirPositive = result.DutVolumeCm > 0.0;
if (!dirPositive.HasValue)
{
dirPositive = channelDirPositive;
}
if (dirPositive != channelDirPositive)
{
return false;
}
}
return true;
}
/// <inheritdoc />
/// <summary>
/// the first measurement is ALWAYS a FlowTestRecord due to the underlying<see cref="GetAllMeasurementResults"/> routine logic.
/// </summary>
public MeasurementResults GetMainMeasurementResult(Double? refVolume, Double? refTimeS, Boolean intermediateMeasurement = false, MeasurementDirection dir = MeasurementDirection.TakeBoth)
{
if (!intermediateMeasurement && GetMeasurementState(0) != MeasurementStates.IsCompleted)
{
throw new ApplicationException("Measurement is not completed");
}
return GetAllMeasurementResults(refVolume, refTimeS, intermediateMeasurement, 0).First();
}
/// <summary>
/// The first measurement is ALWAYS a FlowTestRecord.
/// </summary>
public List<MeasurementResults> GetAllMeasurementResults(Double? refVolume, Double? refTimeS, Boolean intermediateMeasurement = false, Int32? channel = null, MeasurementDirection dir = MeasurementDirection.TakeBoth)
{
//
if (!intermediateMeasurement && GetMeasurementState(channel) != MeasurementStates.IsCompleted)
{
throw new ApplicationException("Measurement is not completed");
}
var mainMeasurement = _listOfIMeasurement.FirstOrDefault(m => m.GetType() == typeof(FlowTestRecord));
if (mainMeasurement == null)
{
throw new ApplicationException("Can not find an ongoing measurement");
}
mainMeasurement.FlowDirectionforCalculatingVol = dir;
var results = new List<MeasurementResults>();
var mainResult = intermediateMeasurement
? mainMeasurement.GetIntermediateMeasurementResult(refVolume, refTimeS)
: mainMeasurement.GetFinalMeasurementResult(refVolume, refTimeS);
results.Add(mainResult);
Logger.Info($"Slot:{Slot}, Channel:{mainMeasurement.GetChannel()} - MeasuredTime({mainResult.DutTimeS}s), " +
$"MeasuredVolume({mainResult.DutVolumeCm}Qm)");
foreach (var otherMeasurement in _listOfIMeasurement.Where(m => m.GetType() != typeof(FlowTestRecord)))
{
try
{
var otherResults = intermediateMeasurement
? otherMeasurement.GetIntermediateMeasurementResult(refVolume, refTimeS)
: otherMeasurement.GetFinalMeasurementResult(refVolume, refTimeS);
Logger.Info($"Slot:{Slot}, Channel:{otherMeasurement.GetChannel()} - ChannelTime({otherResults.DutTimeS}s), " +
$"ChannelVolume({otherResults.DutVolumeCm}Qm)");
results.Add(otherResults);
}
catch (Exception ex)
{
Logger.Warn($"Slot:{Slot}, No Results for channel:{otherMeasurement.GetChannel()} Ex: {ex.Message}");
if (channel == null)
{
throw new ApplicationException($"Can not read result from channel:{otherMeasurement.GetChannel() } Ex: {ex.Message}");
}
}
}
return results;
}
private void AddData(IMeasurementRecord newRecord)
{
foreach (var measurement in _listOfIMeasurement)
{
if (measurement.GetType() != newRecord.GetType())
{
continue;
}
if (measurement.GetChannel() == newRecord.GetChannel())
{
measurement.AddData(newRecord);
}
}
// when every measurement has state IsRunning or every measurement has state IsCompleted, the streaming buffer set to skip decoding
if (_listOfIMeasurement.All(m => m.MeasurementState == MeasurementStates.IsRunning)
|| _listOfIMeasurement.All(m => m.MeasurementState == MeasurementStates.IsCompleted))
{
SyncStreamingBuffer(QualityWatchMode
? SyncMarkRecord.DecodeIntermediateQuality
: SyncMarkRecord.SkipDecoding);
}
}
private void Measurement_ActionStateHasChanged(Object sender, EventArgs e)
{
SyncStreamingBuffer(SyncMarkRecord.DecodeIntermediate);
}
/// <inheritdoc />
public MeasurementStates GetMeasurementState(Int32? onlyChannelNr = null)
{
Logger.Trace($"Slot:{Slot} - Get measurement state");
if (!_listOfIMeasurement.Any())
{
return MeasurementStates.NotStarted;
}
if (onlyChannelNr.HasValue)
{
var measurement = _listOfIMeasurement.First(f => f.GetChannel() == onlyChannelNr.Value);
return measurement.GetMeasurementState();
}
return _listOfIMeasurement.Min(m => m.MeasurementState);
}
/// <inheritdoc />
public Boolean RequestIntermediateMeasurementState(Int32? onlyChannelNr = null)
{
Logger.Trace($"Slot:{Slot} - Get measurement state");
if (!_listOfIMeasurement.Any())
{
return false;
}
Boolean? ret = null;
foreach (var item in _listOfIMeasurement)
{
if (!onlyChannelNr.HasValue || item.GetChannel() == onlyChannelNr.Value)
{
var measurement = _listOfIMeasurement.First(f => onlyChannelNr != null && f.GetChannel() == onlyChannelNr.Value);
if ((measurement.MeasurementState == MeasurementStates.IsRunning
|| measurement.MeasurementState == MeasurementStates.IsWaitingForIntermediateData))
{
measurement.RequestIntermediateRecord();
if (!ret.HasValue)
{
ret = true;
}
}
else
{
ret = false;
}
}
}
return ret.HasValue ? ret.Value : false;
}
}
}