/// /// Copyright (c) 2013-2020 Sensus Slovensko a.s. /// using System; using System.Text; using System.IO.Ports; using System.Collections.Generic; using Config.Entities; using Dirichlet.Numerics; using TBF.BenchControl.Generic; using TBF.BenchControl.GenericDevices; using log4net; namespace TBF.BenchControl.Elde { public class ControlBoardDev : ComponentBase, IDevice, IValveControl { private static readonly ILog log = LogManager.GetLogger(typeof(ControlBoardDev)); public override string ToString() { return string.Format("ControlBoard({0})", Cfg.ToString(1)); } const int FiltersCount = 8; readonly ControlBoardCfg controlBoardCfg; /// /// Reference to the control board component /// IControlCom controlCom; /// /// Emergency stop signal state updated by RunDevice(). /// 'modelessDlg' is notified about the changes and uses this information to change its visibility. /// //UiBridge.EmergencyStopEventArgs.State emergencyStopState; /// /// Public read only wrappers for Elde software component fields /// /// rvNr1 = 1 .. nrRegulValves (one based) /// wmNr0 = 0 .. nrWaterMeters-1 (zero based) /// tmpNr0 = 0 .. nrTempMeters-1 (zero based) /// prsNr0 = 0 .. nrPressureMeters-1 (zero based) /// public StatusP StatusP { get { return controlCom.StatusP; } } public int EtPulses(int wmNr1) { return controlCom.EtPulses(wmNr1); } public int EtPulsesK { get { return controlCom.EtPulsesK; } } public int EtPulses2 { get { return controlCom.EtPulses2; } } /// DEWA_300: pulses from I12 public int EtPulses3 { get { return controlCom.EtPulses3; } } /// DEWA_300: pulses from I13 public UInt16 WMeterPulses(int wmNr1) { return controlCom.WMeterPulses(wmNr1); } public int WMeterReference(int wmNr0) { return controlCom.WMeterReference(wmNr0); } public uint RegulValveDAC(int rvNr0) { return controlCom.RegulValveDAC(rvNr0); } public float Pressure(int prsNr0) { return controlCom.Pressure(prsNr0); } public float Temperature(int tmpNr0) { return controlCom.Temperature(tmpNr0); } public RegulValveState RegulValveState(int rvNr1) { return (RegulValveState)controlCom.RegulValveState(rvNr1); } public UInt128 RRoute { get { return controlCom.RRoute; } } public uint DivTime(int id) { return controlCom.DivTime(id); } public float TTime { get { return controlCom.TTime; } } public float ImpulseTime(int wmNr1) { return controlCom.ImpulseTime(wmNr1); } public uint FmState { get { return controlCom.FmState; } } public uint BeginState(int wmNr0) { return controlCom.BeginState(wmNr0); } public double ReferenceFreq { get { return controlCom.ReferenceFreq; } } /// In [Hz] 0..2500, nom.=2000 public double ReferenceFreqs(int i) { return controlCom.ReferenceFreqs(i); } public double ReferenceFlow { get { return controlCom.ReferenceFlow; } } public float RValvePosition(int rvNr1) { return controlCom.RValvePosition(rvNr1); } public float DivSamples(int time, int divIx0) { return controlCom.DivSamples(time, divIx0); } /// Time unit is 2 ms public int ScopeSamples(int i, int j, int k) { return controlCom.ScopeSamples(i, j, k); } public ulong DigitalInputs { get { return controlCom.DigitalInputs; } } public float AnalogInput(int adcNr0) { return controlCom.AnalogInput(adcNr0); } public uint AnalogInputRaw(int adcNr0, int bank) { return controlCom.AnalogInputRaw(adcNr0, bank); } /// adcNr0: 0=RV1, 1=RV2,... bank: 0=RV, 1=Temp public float ReferenceVolume { get { return controlCom.TotalRefVolume; } } public float VyslExt(int wmNr0, int what) { return controlCom.VyslExt(wmNr0, what); } public uint[] CyclePar { get { return controlCom.CyclePar; } set { controlCom.CyclePar = value; } } public uint[] WMeterCont { get { return controlCom.WMeterCont; } } public bool ManualUIAllowed { get { return controlCom.ManualUIAllowed; } set { controlCom.ManualUIAllowed = value; } } public float ValveOpenCloseTime { get { return controlCom.ValveOpenCloseTime; } } /// Extracted from the StatusP in RunDeviceBefore public bool EmergencyStop { get { return emergencyStop; } } bool emergencyStop; bool previousEmergencyStop; public void DiverterToTank(int flowMtrNr) { cbCommandQueue.Enqueue(new SendCommandArgs(Command.Start, flowMtrNr, int.MaxValue, int.MaxValue, TestMethods.Diverter | TestMethods.Synchro, StopDevs.None)); } /// public void DiverterToSink(int flowMtrNr) { cbCommandQueue.Enqueue(new SendCommandArgs(Command.Stop, 0, 0, 0, TestMethods.Diverter, StopDevs.Diverter | StopDevs.GatePulse | StopDevs.Reference | StopDevs.RegValveRegulation)); } /// public void ReadDiverterTransition(int flowMtrNr) { cbCommandQueue.Enqueue(new SendCommandArgs(Command.ReadDivTransition, flowMtrNr, 0, 0, TestMethods.Diverter, 0)); } /// /// Initialization data updated by constructors of children components /// and sent to 'controlCom2panel' by SendCalibData() method. /// #if DEWA_300 || ROMA_200 public float[,] TempCalibData = new float[16, 5]; #else public float[,] TempCalibData = new float[8, 5]; #endif public uint[] DiverterEdge; /// Created and initialized in this.Initialize() public byte MeretProtocol = 0; // Array length is the reference flowmeters count plus one #if ALZIR_25 || BADGER_MALA_TRAT || BADGER_STREDNA_TRAT || BAHRAIN_50 || CEVAK_40 || FEWA_50 || FILIPINY_50 || FUZHOU_50 || FUZHOU_100 || HONGKONG_50 || IZRAEL_25 || JUZNA_AFRIKA_50 || KEMPNO_50 || KRAKOW_50 || LUXEMBURG_40 || MUNICH || MURES_40 || PETERSBURG_50 || SLM_50 || TORINO_50 || TORUN_50 || TURA_IPERL || TURA_IPERL_NEW || TURA_SPECIAL || WARSAW_50 || ZAMBIA || ZODINO public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}}; #if IZRAEL_50 public byte[] MeretRS485Address = new byte[6]; #else public byte[] MeretRS485Address = new byte[4]; #endif public float[] EtCalib = new float[5] { 1, 1, 1, 1, 1 }; #elif CEVAK_200 || DN100 || FUZHOU_150 || FUZHOU_300 || IZRAEL_200 || SENTEC public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}}; public byte[] MeretRS485Address = new byte[4]; public float[] EtCalib = new float[6] { 1, 1, 1, 1, 1, 1 }; #elif BERLIN || GELSENWASSER || GENESIS || PETERSBURG_200 || PUCHONG_200 || RUM_MOB || SLM_150 public uint[,] RegValveCalib = new uint[16, 2] { {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500} }; public byte[] MeretRS485Address = new byte[4]; public float[] EtCalib = new float[7] { 1, 1, 1, 1, 1, 1, 1 }; #elif DEWA_300 public uint[,] RegValveCalib = new uint[16, 2] { {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500} }; public byte[] MeretRS485Address = new byte[4]; public float[] EtCalib = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 }; #elif ROMA_200 public uint[,] RegValveCalib = new uint[16, 2] { {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500} }; public byte[] MeretRS485Address = new byte[5]; public float[] EtCalib = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 }; #elif IZRAEL_50 || SLM_END public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}}; public byte[] MeretRS485Address = new byte[7]; /// Modbus addresses of Pr1, Pr2, Pr3, Pr4, Pr5, Pr6, T9 (Izrael) or Pr1, Pr2, Pr3, Pr4, T9, T10 (SLM END) public float[] EtCalib = new float[5] { 1, 1, 1, 1, 1 }; #elif WARSAW_END public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}}; public byte[] MeretRS485Address = new byte[4]; public float[] EtCalib = new float[5] { 1, 1, 1, 1, 1 }; #elif MALTA_WSD25 public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}}; public byte[] MeretRS485Address = new byte[12]; public float[] EtCalib = new float[9] { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; #elif BADGER_VELKA_TRAT public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}}; public byte[] MeretRS485Address = new byte[4]; public float[] EtCalib = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 }; #endif public uint[] BalanceRange = new uint[2]; Queue cbCommandQueue; /// /// Route: 128-bit word representing the current state of all valves and pumps /// public UInt128 Route { get { return benchModelRoute; } } UInt128 benchModelRoute; UInt128 valvesToInvert; /// Route = valesToInvert ^ RequiredRouteWithoutInvertedVlaves readonly UInt128 routeMask; /// This mask masks out virtual valves, routeMask is set in the constructor int[] filters; float[] FMFreq; int regConst; int shortImp; /// /// Set values to be applied during a test /// /// Filters for meter pulses /// PID coefficient for flow control /// Short pulses mode (0 = off) public void SetFiltersPidShortPulses(int[] filters, float pid, int shortPulses) { this.filters = filters; this.regConst = (int)pid; this.shortImp = shortPulses; } /// /// Sets the power of the selected pump /// /// Pump index 0 .. 5, invalid pump index sets all pumps to 0% /// Power (0.0f .. 100.0f) public void SetFMFreq(int index, float power) { bool pumpPowerChanged = false; #if DN100 || FUZHOU_150 || MUNICH if ((FMFreq == null) || (FMFreq.Length != 2)) { FMFreq = new float[2]; pumpPowerChanged = true; /// Forces sending a command using Command.None } #elif SLM_END || WARSAW_END if ((FMFreq == null) || (FMFreq.Length != 4)) { FMFreq = new float[4]; pumpPowerChanged = true; /// Forces sending a command using Command.None } #else /// all newer benches if ((FMFreq == null) || (FMFreq.Length != 6)) { FMFreq = new float[6]; pumpPowerChanged = true; /// Forces sending a command using Command.None } #endif if (index >= 0 && index < FMFreq.Length) { if (FMFreq[index] != power) { FMFreq[index] = power; pumpPowerChanged = true; /// Forces sending a command using Command.None string s = string.Format("FMFreq=[{0}{1}{2}{3}{4}{5}]", FMFreq[0].ToString(), (FMFreq.Length > 1) ? ("," + FMFreq[1].ToString()) : "", (FMFreq.Length > 2) ? ("," + FMFreq[2].ToString()) : "", (FMFreq.Length > 3) ? ("," + FMFreq[3].ToString()) : "", (FMFreq.Length > 4) ? ("," + FMFreq[4].ToString()) : "", (FMFreq.Length > 5) ? ("," + FMFreq[5].ToString()) : ""); log.Warn(s); } } else { log.ErrorFormat("Wrong FM pump: index = {0}, power = {1}", index, power); } } public void UpdateWeights() { /// Mettler-Toledo scales for (int i = 0; i < MettlerToledo.Standard.BalanceDev.BalancesCount; i++) { controlCom.SetWeight(i, MettlerToledo.Standard.BalanceDev.Masses[i]); } /// Mettler-Toledo-multi scales (Badger Brno, ...) for (int i = 0; i < MettlerToledo.Multi.BalanceDev.BalancesCount; i++) { controlCom.SetWeight(i, MettlerToledo.Multi.BalanceDev.Masses[i]); } /// Tanks (CEVAK, ...) int firstTankIx = Math.Max(MettlerToledo.Standard.BalanceDev.BalancesCount, MettlerToledo.Multi.BalanceDev.BalancesCount); for (int i = 0; i < Various.TankWithLevelMsrmnt.Tank.TanksCount; i++) { controlCom.SetWeight(firstTankIx + i, Various.TankWithLevelMsrmnt.Tank.Tanks[i].Volume); } } public void SetReservoirTemp(int nr, float temp) { controlCom.SetReservoirTemp(nr, temp); } public ControlBoardDev() { } /// /// Constructor /// public ControlBoardDev(Generic.IComponentCfg cfg) : base(cfg) { controlBoardCfg = cfg as ControlBoardCfg; cbCommandQueue = new Queue(); lastSentFilters = new uint[FiltersCount]; #if DN100 || FUZHOU_150 || MUNICH FMFreq = new float[2] { 0, 0 }; /// Nr. of pumps: Fuzhou150=2, Fuzhou300=6, newer=6 #elif SLM_END || WARSAW_END FMFreq = new float[4] { 0, 0, 0, 0 }; #else /// all newer benches FMFreq = new float[6] { 0, 0, 0, 0, 0, 0 }; #endif emergencyStop = false; previousEmergencyStop = false; routeMask = 0; for (int i = 0; i < 128; i++) { if (i < controlBoardCfg.VirtualValvesRangeLo || i > controlBoardCfg.VirtualValvesRangeHi) { routeMask = routeMask | ((UInt128)1 << i); } } log.Debug(this.ToString()); } /// /// Specific pre-initialization for control board only /// /// public void InitializeComponent( #if DN100 ControlCom2VB.ControlCom2panel ctrlBrdComponent, #elif FUZHOU_150 || MUNICH ControlComponent3Munich.UserControl1 ctrlBrdComponent, #elif FUZHOU_300 ControlComponent3F300.UserControl1 ctrlBrdComponent, #elif BERLIN || GELSENWASSER || GENESIS || IZRAEL_200 || PETERSBURG_200 || PUCHONG_200 || SLM_150 ControlComponent_Izrael2014.UserControl1 ctrlBrdComponent, #else /// all newer benches ControlComponent_Torino2015.UserControl1 ctrlBrdComponent, #endif UInt128 valvesToInvert, double[] tankCapacities) { this.valvesToInvert = valvesToInvert; this.benchModelRoute = valvesToInvert; if (controlBoardCfg.DebugLevel == DebugMode.Simulate) { controlCom = new ControlComSim(); } else { /// Default number of scales (and BalanceRange length) is 2. /// If there are more scales, BalanceRange length is larger. int scalesCnt = Math.Max(2, tankCapacities.Length); BalanceRange = new uint[scalesCnt]; for (int i = 0; i < scalesCnt; i++) { BalanceRange[i] = (uint)((i < tankCapacities.Length) ? tankCapacities[i] : 0); } controlCom = new ControlComWrap(ctrlBrdComponent); } } /// Initialize this device public void Initialize() { int divertersCount = BenchControl.Elde.Diverter.Diverter.DivertersCount; DiverterEdge = new uint[divertersCount]; for (int i = 0; i < divertersCount; i++) { DiverterEdge[i] = (uint)BenchControl.Elde.Diverter.Diverter.Diverters[i].ThresholdGate; controlCom.SetDivLimit(i, (uint)BenchControl.Elde.Diverter.Diverter.Diverters[i].ThresholdLo, (uint)BenchControl.Elde.Diverter.Diverter.Diverters[i].ThresholdHi); } controlCom.SendCalibData(RegValveCalib, MeretRS485Address, controlBoardCfg.ComPortNr, TempCalibData, EtCalib, DiverterEdge, BalanceRange, MeretProtocol); log.FatalFormat("Successfully initialized device {0}", ToString()); } /// /// Run this device /// public void RunDeviceBefore() { if (DebugLevel == DebugMode.Simulate) return; controlCom.RunDeviceBefore(); SyncRoute(); } /// /// Used in RunDeviceAfter() when sending commands /// UInt128 lastSentRoute; uint[] lastSentFilters; float[] lastSentFMFreq; int lastsentRegConst; int lastSentShortImp; /// /// Run this device /// public void RunDeviceAfter() { if (DebugLevel == DebugMode.Simulate) return; previousEmergencyStop = emergencyStop; emergencyStop = (controlCom.StatusP & StatusP.EmgcyStopActive) != 0; /// if (emergencyStop) { /// Modify the queue in case of an emergency stop cbCommandQueue.Clear(); cbCommandQueue.Enqueue(new SendCommandArgs(Command.Stop, 0, 0, 0, 0, StopDevs.All)); } /// if (emergencyStop && !previousEmergencyStop) { /// Stop the cycle - Press 'STOP' button in the BenchControlPanel TBF.UiBridge.Bridge.Ui2Bench(TBF.UiBridge.UI2BenchCmd.Stop); Program.MainWnd.Invoke(new ShowEmergencyStopFormDlgt(ShowEmergencyStopForm)); } else if (!emergencyStop && previousEmergencyStop) { UiBridge.Bridge.OnEmergencyStopChanged(this, UiBridge.EmergencyStopEventArgs.State.CloseForm); } UpdateWeights(); /// Prepare uintFilters array and evaluate changes uint[] uintFilters = new uint[FiltersCount]; uintFilters[0] = (filters != null && filters.Length > 0) ? (uint)filters[0] : 0; bool filtersAreDifferent = (uintFilters[0] != lastSentFilters[0]); for (int i = 1; i < FiltersCount; i++) { uintFilters[i] = (filters != null && filters.Length > i) ? (uint)filters[i] : uintFilters[i - 1]; filtersAreDifferent |= (uintFilters[i] != lastSentFilters[i]); } /// Evaluate FMFreq changes bool fmFreqsAreDifferent = false; if ((FMFreq == null) || (lastSentFMFreq == null) || (FMFreq.Length != lastSentFMFreq.Length)) { fmFreqsAreDifferent = true; } else { for (int i = 0; i < FMFreq.Length; i++) { if (FMFreq[i] != lastSentFMFreq[i]) { fmFreqsAreDifferent = true; break; } } } if (cbCommandQueue.Count > 0) { /// /// There is a command in the queue /// controlCom.SendCommand(cbCommandQueue.Dequeue(), (benchModelRoute & routeMask), uintFilters, FMFreq, regConst, shortImp); lastSentRoute = (benchModelRoute & routeMask); lastsentRegConst = regConst; lastSentShortImp = shortImp; /// Deep copy of arrays lastSentFilters and lastSentFMFreq if ((lastSentFilters == null) || (lastSentFilters.Length != uintFilters.Length)) lastSentFilters = new uint[(uintFilters == null) ? 0 : uintFilters.Length]; for (int i = 0; i < lastSentFilters.Length; i++) lastSentFilters[i] = uintFilters[i]; if ((lastSentFMFreq == null) || (lastSentFMFreq.Length != FMFreq.Length)) lastSentFMFreq = new float[(FMFreq == null) ? 0 : FMFreq.Length]; for (int i = 0; i < lastSentFMFreq.Length; i++) lastSentFMFreq[i] = FMFreq[i]; } else if (((benchModelRoute & routeMask) != lastSentRoute) || filtersAreDifferent || fmFreqsAreDifferent || (lastsentRegConst != regConst) || (lastSentShortImp != shortImp)) { /// /// Command queue is mepty, but 'route', pump frequency, PID coef., filters or shortImp have changed /// controlCom.SendCommand(new SendCommandArgs(Command.None, 0, 0, 0, 0, 0), (benchModelRoute & routeMask), uintFilters, FMFreq, regConst, shortImp); lastSentRoute = (benchModelRoute & routeMask); lastsentRegConst = regConst; lastSentShortImp = shortImp; /// Deep copy of arrays lastSentFilters and lastSentFMFreq if ((lastSentFilters == null) || (lastSentFilters.Length != uintFilters.Length)) lastSentFilters = new uint[(uintFilters == null) ? 0 : uintFilters.Length]; for (int i = 0; i < lastSentFilters.Length; i++) lastSentFilters[i] = uintFilters[i]; if ((lastSentFMFreq == null) || (lastSentFMFreq.Length != FMFreq.Length)) lastSentFMFreq = new float[(FMFreq == null) ? 0 : FMFreq.Length]; for (int i = 0; i < lastSentFMFreq.Length; i++) lastSentFMFreq[i] = FMFreq[i]; } controlCom.RunDeviceAfter(); } /// Stop this device public void StopDevice() { } public void StopDevice2() { } delegate void ShowEmergencyStopFormDlgt(); /// void ShowEmergencyStopForm() { (new TBF.UI.Shared.EmergencyStopForm()).Show(); } /// /// Sends a command to the control board. /// /// See ControlBoard.Command enum /// Number of the etalon/reference (1..5) /// State of valves, 128-bit word /// kolko impulzov ma trvat skuska /// See ControlBoard.TestMethods enum /// 0 = No filtering (0..255) /// Coefficient used to control reg. valves (1..100) /// 0 = default value, 1 = spec. processing of very short pulses /// What to stop public void SendCommand(Command cmd, int refFlowmtrNr, int totalRefPulses, int massRefPulses, TestMethods testMethods, StopDevs stopDevs) { cbCommandQueue.Enqueue(new SendCommandArgs(cmd, refFlowmtrNr, totalRefPulses, massRefPulses, testMethods, stopDevs)); } /// /// Set valves to new positions. /// /// 'ulong' with bits of valves to open set to '1' /// 'ulong' with bits of valves to close set to '1' /// 'ulong' with bits of valves that have changed set to '1' public UInt128 SetValves(UInt128 valvesToOpen, UInt128 valvesToClose, IList extendedValves) { UInt128 oldRoute = benchModelRoute; benchModelRoute = (((benchModelRoute ^ valvesToInvert) | valvesToOpen) & (~valvesToClose)) ^ valvesToInvert; foreach (var extV in extendedValves) extV.UpdateRoute(ref benchModelRoute); log.DebugFormat("SetValves(x,x), new route = {0}", Utils.RouteToStr(benchModelRoute)); return oldRoute ^ benchModelRoute; } /// /// Set Route to value returned by RRoute. Take virtual valves into account. /// /// 'ulong' with bits of valves that have changed set to '1' public UInt128 SyncRoute() { UInt128 oldRoute = benchModelRoute; benchModelRoute = (RRoute & routeMask) | (benchModelRoute & (~routeMask)); log.DebugFormat("SyncRoute(), new route = {0}", Utils.RouteToStr(benchModelRoute)); return oldRoute ^ benchModelRoute; } /// /// Regulation valves control. /// /// Regulation valve nr. (1..5) /// Valve regulation mode, see the enum /// Target position or target frequency or pulse duration /// Stabilization time when setting the flow: 0=200ms, step 50ms, max. 1.5 sec. public void ValveMove(int valveNo, RegulValveMode valveMode, float[] valveValue, int stableTime) { controlCom.ValveMove(valveNo, valveMode, valveValue, stableTime); } /// /// Open one valve and/or close one valve. /// Events: ValvesSet /// /// Valve to be opened /// Valve to be closed /// Created operation public IOperation SetValvesOp(IValve valveOpen, IValve valveClose) { return new SetValvesOp(this, valveOpen, valveClose); } /// /// Open and/or close multiple valves. /// Events: ValvesSet /// /// A list of valves to be opened /// A list of valves to be closed /// Created operation public IOperation SetValvesOp(IList valvesOpen, IList valvesClose) { return new SetValvesOp(this, valvesOpen, valvesClose); } /// /// Starts the measurement. /// Events: MeasurementStarted /// /// Flow meter /// An array of register readers /// Number of reference pulses to complete the test /// Created operation public IOperation StartMeasurementOp(OutputPath outputPath, TestMethods method, double requiredFlowLo, double requiredFlowHi, int refPulses, int delayBeforeFlowRegulation = 0) { if (controlBoardCfg.DebugLevel == DebugMode.Simulate) { return new Operations.ReturnGivenEventOp(Event.MeasurementStarted); } else { return new StartMeasurementOp(this, outputPath, method, requiredFlowLo, requiredFlowHi, refPulses, delayBeforeFlowRegulation); } } /// /// Starts the measurement. /// Events: MeasurementStarted /// /// Flow meter /// An array of register readers /// Number of reference pulses to complete the test /// Created operation public IOperation StartProlongedMeasurementOp(OutputPath outputPath, TestMethods method, double requiredFlowLo, double requiredFlowHi, int totalRefPulses, int massRefPulses, int delayBeforeFlowRegulation = 0) { if (controlBoardCfg.DebugLevel == DebugMode.Simulate) { return new Operations.ReturnGivenEventOp(Event.MeasurementStarted); } else { return new StartMeasurementOp(this, outputPath, method, requiredFlowLo, requiredFlowHi, totalRefPulses, massRefPulses, delayBeforeFlowRegulation); } } /// /// Read diverter samples from the control board and calculated the transition time. /// Events: Event.None /// /// Diverter /// State machine ticks from test start/end when diverter read command is issued (obsolete) /// State machine ticks from test start/end when diverter samples are read /// FloatBox for the resulting transition time in s /// Statistics for plotting diverter transitions /// Batch number /// Test name (without repetitions) /// Repetition number /// Created operation public IOperation ReadDiverterTransitionOp(IDiverter div, int runsCountWhenSendingCmd, int runsCountWhenReadingDiv, bool toTank, Sequences.Statistics plotter, int batchNr, string testName, int repetition) { if (controlBoardCfg.DebugLevel == DebugMode.Simulate) { return new Operations.ReturnGivenEventOp(Event.None); } else { return new ReadDiverterTransitionOp(this, div, runsCountWhenSendingCmd, runsCountWhenReadingDiv, toTank, plotter, batchNr, testName, repetition); } } /// /// Queries th econtrol board whether the measurement was completed. /// Events: MeasurementCompleted or None /// /// Created operation public IOperation QueryMeasurementEndOp() { return new QueryMeasurementEndOp(this); } /// /// Stop controls board flow regulation operation /// Events: FlowRegulationStopped /// /// Created operation public IOperation StopFlowRegulationOp(OutputPath outputPath) { return new StopFlowRegulationOp(this, outputPath); } /// /// Stop the previous control board operation (diverter, gate, etc.) /// Events: PreviousStopped /// /// Created operation public IOperation StopPreviousOp() { return new StopPreviousOp(this); } /// /// Sends commands to the control board. /// Events: Event.None, Event.CommandCompleted /// /// Command sent to CB when this operation starts /// Command sent to CB when this operation stops /// Test method parameter /// Created operation public IOperation ExecuteCommandOp(Command commandOnStartOp, Command commandOnStopOp, TestMethods testMethod) { return new ExecuteCommandOp(this, commandOnStartOp, commandOnStopOp, testMethod); } } }