///
/// 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;
}
}
}
}