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 { /// /// Check the positioning of the streaming LED to validate the quality of the communication line /// public class GenesisMeterStreamingQuality : GenesisMeter { /// /// Backup of last quality /// public QualityResult LastQualityResult; private StreamingDecoder _sd; /// /// Quality check is active /// public Boolean IsRunning; private DateTimeOffset? _startTime; private DateTimeOffset? _stopTime; private List _collectedRecords; private Int32? _tillDecodedCount; /// /// Kick off the streaming quality check. /// /// /// 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(); 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); } } } } /// /// Stop the streaming check. /// /// /// /// 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(); } /// /// /// public class QualityResult { /// /// Number of records received (read line for LED message) /// public readonly Int32 TotalLinesCount; /// /// Total records decoded /// public readonly Int32 TotalDecodedCount; /// /// Total errors /// public readonly Int32 TotalTransportErrorCount; /// /// Validated without errors /// public readonly Int32 TotalValidationWithoutErrorsCount; /// /// Expected lines /// public readonly Int32 ExpectedLinesCount; /// /// Time /// public readonly TimeSpan TotalTime; /// /// Error counter /// public readonly Dictionary ErrorOccurredCounter; /// /// The real result of quality check /// /// /// /// public QualityResult(List collectedRecords, TimeSpan ts, Int32 sampleRateHz) { TotalLinesCount = collectedRecords.Count; TotalTime = ts; ExpectedLinesCount = (Int32)(Math.Round(ts.TotalSeconds * sampleRateHz, 0)); ErrorOccurredCounter = new Dictionary(); 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; if (flowTestRecord != 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); } } } } } /// /// The quality result as dummy zero /// public QualityResult() { TotalLinesCount = 0; TotalTime = TimeSpan.Zero; ErrorOccurredCounter = new Dictionary(); } } } }