/// /// Copyright (c) 2021 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Xml.Serialization; using log4net; using Config.Entities; using DataStreamInterface; using TBF.BenchControl; using TBF.BenchControl.Generic; using TBF.BenchControl.RegisterReaders.DataStream; namespace TBF.BenchControl.RegisterReaders.DataStream.Reader { /// /// Holds information identifying the test bench. /// public class Reader : ComponentBase, IOperation, GenericDevices.IRegReaderDatastream { private static readonly ILog log = LogManager.GetLogger(typeof(Reader)); public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } const Int64 MinSamplesCount = 20; MefImport.MefImport mefImport; Int64 minSamplesCount { get { return mefImport.MinSamplesCount; } } /// /// IRegReader interface part 1 /// readonly ReaderCfg myCfg; public RegisterReaderType RegisterReaderType { get { return RegisterReaderType.DataStream; } } public int Position { get { return (myCfg != null) ? myCfg.Position : 1; } } public double PulsesPerLtr { get { return 1.0; } } public double LtrsPerPulse { get { return 1.0; } } string waterMeterID; Int64 storedFramesCount; Int64 startIx; Int64 endIx; Dictionary samplesDict; DataStreamInterface.Unit timeUnit; DataStreamInterface.Unit volumeUnit; public Reader() { } public Reader(Generic.IComponentCfg cfg, IList components) : base(cfg) { myCfg = cfg as ReaderCfg; mefImport = TbfComponents.FindComponent(cfg.ParentName, components) as MefImport.MefImport; if (mefImport == null) throw new Exception("Cannot find " + Name + " parent"); } public override void Initialize() { if (DebugLevel == DebugMode.Normal) { if (Position < 1 || Position > Math.Min(Config.Data.WMsCount, mefImport.DataStreamIFace.GetMetersCount())) { throw new ArgumentException("Position is out of range"); } samplesDict = new Dictionary(); log.FatalFormat("{0} initialized: {1}", Name, this); } else { log.FatalFormat("{0} simulated: {1}", Name, this); } } /// /// IRegReader interface part 2 /// int wmPulses; int wmRefPulses; double wmVolume; double beginWMState; double endWMState; /// public int WMPulses { get { return wmPulses; } } /// Counted pulses of the water meter public int WMRefPulses { get { return wmRefPulses; } } /// 'Gated' reference pulses of the water meters public double WMVolume { get { return wmVolume; } } /// Counted volume of the water meter public double BeginWMState { get { return beginWMState; } } /// Test begin state of the water meter public double EndWMState { get { return endWMState; } } /// Test end state of the water meter /// To be used at the beginning of a test public void Clear() { storedFramesCount = 0; startIx = -1; endIx = -1; beginWMState = 0; endWMState = 0; wmVolume = 0; wmPulses = 0; wmRefPulses = 0; samplesDict.Clear(); timeUnit = DataStreamInterface.Unit.s; volumeUnit = DataStreamInterface.Unit.l; } /// To be used when the test is completed ... public void TestCompleted() { mefImport.DataStreamIFace.CloseConnection(Position - 1); } public IOperation ReadRegisterOp() { return this; } /// /// IOperation interface /// public void Start() { Clear(); mefImport.DataStreamIFace.OpenConnection(Position - 1, "", out waterMeterID); timeUnit = mefImport.DataStreamIFace.GetTimeUnits(); volumeUnit = mefImport.DataStreamIFace.GetVolumeUnits(); mefImport.DataStreamIFace.StartMeasurement(Position - 1); } public Event Run() { return Event.None; } public void Stop() { mefImport.DataStreamIFace.StopMeasurement(Position - 1, out storedFramesCount); if (storedFramesCount >= minSamplesCount) { startIx = storedFramesCount / minSamplesCount; endIx = (storedFramesCount * (minSamplesCount - 1) / minSamplesCount) - 1; beginWMState = VolumeLtrStart; endWMState = VolumeLtrEnd; wmVolume = Math.Abs(VolumeLtrEnd - VolumeLtrStart); wmPulses = (int)Math.Round(wmVolume * PulsesPerLtr); wmRefPulses = StateMachine.ControlBoard.EtPulses(0); } } /// ... for more accurate WMPulses, WMRefPulses calculation /// /// IRegReaderDatastream interface /// public bool NoSamples { get { return storedFramesCount < minSamplesCount || startIx < 0 || endIx < 0; } } public double VolumeLtrStart { get { return (startIx >= 0) ? GetVolumeFromSamples(startIx) : 0; } } public double VolumeLtrEnd { get { return (endIx >= 0) ? GetVolumeFromSamples(endIx) : 0; } } public double TimestampSecStart { get { return (startIx >= 0) ? GetTimeFromSamples(startIx) : 0; } } public double TimestampSecEnd { get { return (endIx >= 0) ? GetTimeFromSamples(endIx) : 0; } } double GetTimeFromSamples(Int64 ix) { DataFrame oneFrame; DataFrame[] frames; if (samplesDict.TryGetValue(ix, out oneFrame)) { return DataStreamInterface.Units.ConvertFrom(timeUnit, oneFrame.Time); } else if ((frames = mefImport.DataStreamIFace.GetFrames(Position - 1, ix, 1)).Length == 1) { samplesDict.Add(ix, frames[0]); return DataStreamInterface.Units.ConvertFrom(timeUnit, frames[0].Time); } else { return 0; } } double GetVolumeFromSamples(Int64 ix) { DataFrame oneFrame; DataFrame[] frames; if (samplesDict.TryGetValue(ix, out oneFrame)) { return DataStreamInterface.Units.ConvertFrom(volumeUnit, oneFrame.Volume); } else if ((frames = mefImport.DataStreamIFace.GetFrames(Position - 1, ix, 1)).Length == 1) { samplesDict.Add(ix, frames[0]); return DataStreamInterface.Units.ConvertFrom(volumeUnit, frames[0].Volume); } else { return 0; } } } }