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

215 lines
7.7 KiB
C#

using System;
using System.Collections.Generic;
using Xylem.Common.CommonCore.Consts;
using Xylem.Common.Hardware.Interfaces.Ports.PortCore.EventArguments;
using Xylem.Common.Hardware.Interfaces.Ports.SerialPorts;
using Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
{
/// <summary>
/// Check the positioning of the streaming LED to validate the quality of the communication line
/// </summary>
public class GenesisMeterStreamingQuality : GenesisMeter
{
/// <summary>
/// Backup of last quality
/// </summary>
public QualityResult LastQualityResult;
private StreamingDecoder _sd;
/// <summary>
/// Quality check is active
/// </summary>
public Boolean IsRunning;
private DateTimeOffset? _startTime;
private DateTimeOffset? _stopTime;
private List<String> _collectedRecords;
private Int32? _tillDecodedCount;
/// <summary>
/// Kick off the streaming quality check.
/// </summary>
/// <param name="tillDecodedCount"></param>
/// <exception cref="ApplicationException"></exception>
public void StartStreamingQualityCheck(Int32? tillDecodedCount = null)
{
if (IsRunning)
{
return;
}
_tillDecodedCount = tillDecodedCount;
if (_tillDecodedCount.HasValue)
{
_sd = new StreamingDecoder(false);
}
if (StreamingPort == null || !(StreamingPort is LedSerialPort))
{
throw new ApplicationException("No valid streaming port");
}
_stopTime = null;
_collectedRecords = new List<String>();
SyncStreamingBuffer(SyncMarkRecord.DecodeEveryPackage);
((LedSerialPort)StreamingPort).OnRawRecordReceived += GenesisMeterStreamingQuality_OnRawRecordReceived;
_startTime = DateTimeOffset.UtcNow;
LogRawData(true);
IsRunning = true;
}
private void GenesisMeterStreamingQuality_OnRawRecordReceived(Object sender, BasePortDataEventArgs e)
{
_collectedRecords.Add(e.GetData().ToString());
if (_tillDecodedCount.HasValue)
{
if (_sd.DecodeMsg(e.GetData().ToString()))
{
_tillDecodedCount = _tillDecodedCount.Value - 1;
if (_tillDecodedCount <= 0)
{
IsRunning = false;
LastQualityResult = StopStreamingQualityCheck(10);
}
}
}
}
/// <summary>
/// Stop the streaming check.
/// </summary>
/// <param name="sampleRateHz"></param>
/// <returns></returns>
/// <exception cref="ApplicationException"></exception>
public QualityResult StopStreamingQualityCheck(Int32 sampleRateHz)
{
_stopTime = DateTimeOffset.UtcNow;
if (!IsRunning && !_startTime.HasValue)
{
return new QualityResult();
}
if (StreamingPort == null || !(StreamingPort is LedSerialPort))
{
throw new ApplicationException("No valid streaming port");
}
LogRawData(false);
((LedSerialPort)StreamingPort).OnRawRecordReceived -= GenesisMeterStreamingQuality_OnRawRecordReceived;
SyncStreamingBuffer(SyncMarkRecord.SkipDecoding);
IsRunning = false;
if (_stopTime != null && _startTime != null)
return new QualityResult(_collectedRecords, _stopTime.Value - _startTime.Value, sampleRateHz);
return new QualityResult();
}
/// <summary>
///
/// </summary>
public class QualityResult
{
/// <summary>
/// Number of records received (read line for LED message)
/// </summary>
public readonly Int32 TotalLinesCount;
/// <summary>
/// Total records decoded
/// </summary>
public readonly Int32 TotalDecodedCount;
/// <summary>
/// Total errors
/// </summary>
public readonly Int32 TotalTransportErrorCount;
/// <summary>
/// Validated without errors
/// </summary>
public readonly Int32 TotalValidationWithoutErrorsCount;
/// <summary>
/// Expected lines
/// </summary>
public readonly Int32 ExpectedLinesCount;
/// <summary>
/// Time
/// </summary>
public readonly TimeSpan TotalTime;
/// <summary>
/// Error counter
/// </summary>
public readonly Dictionary<UInt16, Int32> ErrorOccurredCounter;
/// <summary>
/// The real result of quality check
/// </summary>
/// <param name="collectedRecords"></param>
/// <param name="ts"></param>
/// <param name="sampleRateHz"></param>
public QualityResult(List<String> collectedRecords, TimeSpan ts, Int32 sampleRateHz)
{
TotalLinesCount = collectedRecords.Count;
TotalTime = ts;
ExpectedLinesCount = (Int32)(Math.Round(ts.TotalSeconds * sampleRateHz, 0));
ErrorOccurredCounter = new Dictionary<UInt16, Int32>();
foreach (var rawText in collectedRecords)
{
var sd = new StreamingDecoder(false);
if (!sd.DecodeMsg(rawText))
{
TotalTransportErrorCount++;
continue;
}
//here the decoding is valid including the CRC
TotalDecodedCount++;
//the DecodeMsg has assigned either a DataCalib or DataFlowTest data set
var calibrationRecord = sd.DataCalib;
var flowTestRecord = sd.DataFlowTest;
var bendDetectRecord = sd.DataBendDetectTest;
if (flowTestRecord != null)
{
TotalValidationWithoutErrorsCount++;
continue;
}
if (bendDetectRecord != null)
{
TotalValidationWithoutErrorsCount++;
continue;
}
if (calibrationRecord != null)
{
if (calibrationRecord.Validation == 0)
{
TotalValidationWithoutErrorsCount++;
}
else
{
if (ErrorOccurredCounter.ContainsKey(calibrationRecord.Validation))
{
ErrorOccurredCounter[calibrationRecord.Validation] += 1;
}
else
{
ErrorOccurredCounter.Add(calibrationRecord.Validation, 1);
}
}
}
}
}
/// <summary>
/// The quality result as dummy zero
/// </summary>
public QualityResult()
{
TotalLinesCount = 0;
TotalTime = TimeSpan.Zero;
ErrorOccurredCounter = new Dictionary<UInt16, Int32>();
}
}
}
}