/// /// Copyright (c) 2013-2019 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using System.Text; using Dirichlet.Numerics; using log4net; namespace TBF.BenchControl.Elde { public class ControlComSim : IControlCom { private static readonly ILog log = LogManager.GetLogger(typeof(ControlComSim)); public override string ToString() { return string.Format("ControlComSim"); } StatusP statusP; public StatusP StatusP { get { return statusP; } } double referenceFreq = 650.0; public double ReferenceFreq { get { return referenceFreq; } } public double ReferenceFreqs(int i) { return 0; } int[] etPulses = new int[Config.Data.WMsCount + 1]; public int EtPulses(int wmNr1) { return etPulses[wmNr1]; } public int EtPulsesK { get { return 1; } } public int EtPulses2 { get { return 0; } } public int EtPulses3 { get { return 0; } } double[] errFactor = new double[Config.Data.WMsCount + 1]; /// Internal double[] wMeterPulsesF = new double[Config.Data.WMsCount + 1]; /// Internal UInt16[] wMeterPulses = new UInt16[Config.Data.WMsCount + 1]; /// Rounded from wMeterPulsesF public UInt16 WMeterPulses(int wmNr1) { return wMeterPulses[wmNr1]; } int[] wMeterReference = new int[Config.Data.WMsCount + 1]; public int WMeterReference(int wmNr1) { return wMeterReference[wmNr1]; } public uint RegulValveDAC(int rvNr0) { return 0; } public float Pressure(int prsNr0) { return 0; } public float Temperature(int tmpNr0) { return (float)(20 + tmpNr0); } public RegulValveState RegulValveState(int rvNr1) { return 0; } public UInt128 RRoute { get { return simRoute; } } public uint DivTime(int id) { return 0; } public void SetDivLimit(int divNo, uint limLoPct, uint limHiPct) { } float tTime = 1; public float TTime { get { return tTime; } } public float ImpulseTime(int wmNr1) { return tTime; } public uint FmState { get { return 0; } } public uint BeginState(int wmNr0) { return 0; } double referenceFlow; public double ReferenceFlow { get { return referenceFlow; } } public float RValvePosition(int rvNr1) { return 0; } public float DivSamples(int ms, int divIx0) { return 0; } public int ScopeSamples(int i, int j, int k) { return 0; } public ulong DigitalInputs { get { return 0; } } public float AnalogInput(int adcNr0) { return 0; } public uint AnalogInputRaw(int adcNr0, int bank) { return 0; } /// bank0=RV, bank1=Temp public float TotalRefVolume { get { return 0; } } public float VyslExt(int wmNr0, int what) { return 0; } public void SetWeight(int pos, double mass) { return; } /// not available in sim. mode public uint[] CyclePar { get { return cyclePar; } set { cyclePar = value; } } /// dummy public uint[] WMeterCont { get { return wMeterCont; } } /// dummy public float ValveOpenCloseTime { get { return 0.001f; } } /// public bool ManualUIAllowed { get { return manualUIAllowed; } set { manualUIAllowed = value; } } bool manualUIAllowed = true; public void SetReservoirTemp(int nr, float temp) { } /// /// Private initialization data updated by contructors of children components /// and sent to 'controlCom2panel' by SendCalibData() method. /// uint[,] regValveCalib; byte[] meretRS485Address; float[,] tempCalibData; float[] etCalib; uint[] diverterEdge; uint[] balanceRange; byte meretProtocol; uint[] cyclePar; uint[] wMeterCont; /// /// Private values set by SendCommand() /// Command cmd; int refFlowmtrNr; UInt128 simRoute; int totalRefPulses; int massRefPulses; TestMethods testMethods; uint[] filterConstants; float[] FMFreq; int regConst; int shortImp; StopDevs stopDevs; /// /// Private values set by ValveMove() /// int regulValveNo; RegulValveMode regulValveMode; float[] regulValveValue; Random rand; /// /// Constructor /// public ControlComSim() { rand = new Random(); cyclePar = new uint[163]; wMeterCont = new uint[3] { 1, 2, 3 }; } /// /// Sends calibration and configuration data to the control board. /// /// Regulating valves calib.coefs, ix1 = valve nr. (1..5), ix2 = coef.nr. (0..1), values typ. c0 = 0, c1 = 0.2 /// Meret address, index = 0..1, value typ. 99 and 100 /// COM port number of the control board (typ. 1) /// Temp.calc.coefs, ix1 = temp.sens.nr. (0..7 ???), ix2 = coef.nr /// Etalon nominal values /// Percentages for switching of diverters, ix = diverter nr.(0,1), typ.value 50 (%) public void SendCalibData(uint[,] rvCalib, byte[] meretA, int usedCom, float[,] tempCalib, float[] etCalib, uint[] divEdge, uint[] balanceRange, byte meretProtocol) { log.Info("SendCalibData(...)"); this.regValveCalib = rvCalib; this.meretRS485Address = meretA; this.tempCalibData = tempCalib; this.etCalib = etCalib; this.diverterEdge = divEdge; this.balanceRange = balanceRange; this.meretProtocol = meretProtocol; } /// /// 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) /// Freq.inverter control (not applicable in DT100, Munich) /// Coefficient used to control reg. valves (1..100) /// 0 = default value, 1 = spec. processing of very short pulses /// What to stop public void SendCommand(SendCommandArgs sendCommandArgs, UInt128 route, uint[] filterConstants, float[] fmFreq, int regConst, int shortImp) { log.InfoFormat("SendCommand(Cmd={0},Ref#={1},Route={2} {3} {4} {5},TotalPls={6},MassPls={7},TstM={8},filt={9},FM=[{10}{11}{12}{13}{14}{15}],Reg={16},ShrtImp={17},Stop={18})", sendCommandArgs.Cmd, sendCommandArgs.RefFlowmtrNr, /// 0, 1 ((route >> 48) & 0xFFFF).ToString("X4"), /// 2 ((route >> 32) & 0xFFFF).ToString("X4"), /// 3 ((route >> 16) & 0xFFFF).ToString("X4"), /// 4 (route & 0xFFFF).ToString("X4"), /// 5 totalRefPulses, massRefPulses, testMethods, filterConstants, /// 6, 7, 8, 9 fmFreq[0].ToString(), /// 10 (fmFreq.Length > 1) ? ("," + fmFreq[1].ToString()) : "", /// 11 (fmFreq.Length > 2) ? ("," + fmFreq[2].ToString()) : "", /// 12 (fmFreq.Length > 3) ? ("," + fmFreq[3].ToString()) : "", /// 13 (fmFreq.Length > 4) ? ("," + fmFreq[4].ToString()) : "", /// 14 (fmFreq.Length > 5) ? ("," + fmFreq[5].ToString()) : "", /// 15 regConst, shortImp, stopDevs); /// 16, 17, 18 /// /// Simulation /// Command lastCmd = this.cmd; this.cmd = sendCommandArgs.Cmd; this.refFlowmtrNr = sendCommandArgs.RefFlowmtrNr; #if FUZHOU_300 /// /// The following code deals with the situation that all FM controlled pums share bit #39. /// In settings the bits of pumps should be sent as follows: P1=50, P2=51, P3=52, P4=53, P5=54 and P7=55 /// (in FUZHOU_300 the FM pump bit should be set set to value FMIndex+50). /// bool bit39 = (route & 0x00FC000000000000) != 0; /// true if any of bits 50 through 55 is set route = route & 0xFF03FFFFFFFFFFFF; if (bit39) route = route | 0x0000008000000000; log.DebugFormat("SendCommand route = {0}", Utils.RouteToStr(route)); #endif TestBenchSim.SimRoute = this.simRoute = route; this.totalRefPulses = sendCommandArgs.TotalRefPulses; this.massRefPulses = sendCommandArgs.MassRefPulses; this.testMethods = sendCommandArgs.TestMethods; this.stopDevs = sendCommandArgs.StopDevs; this.filterConstants = filterConstants; this.FMFreq = fmFreq; this.regConst = regConst; this.shortImp = shortImp; #pragma warning disable statusP = (StatusP)(((ulong)statusP & (ulong)0xFFFFFFFFFFFFFFF8L) | (ulong)refFlowmtrNr); #pragma warning restore if (cmd == Command.Start && lastCmd != Command.Start ) { statusP |= StatusP.TestInProgress; /// /// Clear all counters /// if (etPulses != null) { for (int i = 0; i < etPulses.Length; i++) etPulses[i] = 0; } if (wMeterPulses != null) { for (int i = 0; i < wMeterPulses.Length; i++) wMeterPulses[i] = 0; } if (wMeterPulsesF != null) { for (int i = 0; i < wMeterPulsesF.Length; i++) wMeterPulsesF[i] = 0; } if (wMeterReference != null) { for (int i = 0; i < wMeterReference.Length; i++) wMeterReference[i] = 0; } if (errFactor != null) { for (int i = 0; i < errFactor.Length; i++) errFactor[i] = ((float)rand.Next(100) + 950.0f) / 1000.0f; } tTime = 0; } else if (cmd == Command.Stop) { statusP = 0; //statusP &= ~StatusP.Running; } } /// /// Control of regulating valves. /// /// Regulating valve nr. (1..5) /// ??? /// ??? /// Stabilization time when setting the flow: 0=200ms, step 50ms, max. 1.5 sec. public void ValveMove(int regulValveNo, RegulValveMode regulValveMode, float[] regulValveValue, int stableTime) { log.InfoFormat("ValveMove({0}, {1}, [{2},{3}], {4})", regulValveNo, regulValveMode, regulValveValue[0], regulValveValue[1], stableTime); this.regulValveNo = regulValveNo; this.regulValveMode = regulValveMode; this.regulValveValue = regulValveValue; } public void RunDeviceBefore() { log.DebugFormat("RunDeviceBefore() ... regV#={0}, flowM#{1}, statusP={2}", regulValveNo, refFlowmtrNr, statusP.ToString("X")); TestBenchSim.RunDevice(regulValveNo, refFlowmtrNr, statusP); log.DebugFormat("refFreq={0}", referenceFreq); tTime += 1.0f; float Qnom = (regulValveNo > 0) ? etCalib[regulValveNo] : 0; switch (cmd) { case Command.None: break; case Command.Start: if ((testMethods & TestMethods.Diverter) == TestMethods.Diverter) { TestBenchSim.SetSimDiverter(true); } break; case Command.Stop: if ((testMethods & TestMethods.Diverter) == TestMethods.Diverter) { TestBenchSim.SetSimDiverter(false); } break; } switch (regulValveMode) { case RegulValveMode.TargetFrequency: float targetFlow = ((regulValveValue[0] + regulValveValue[1]) / 2.0f) * (Qnom / 2000.0f); TestBenchSim.UpdateSimFlow(targetFlow); //if (referenceFreq < valveValue[0]) referenceFreq += ((float)rand.Next(20) + 10.0f) / 2.0f; //else if (referenceFreq > valveValue[1]) referenceFreq -= ((float)rand.Next(20) + 10.0f) / 2.0f; //else referenceFreq += ((float)rand.Next(10) - 5.0f) / 2.0f; referenceFreq = TestBenchSim.GetSimFlow() * 2000.0 / Qnom; if (referenceFreq < 0) referenceFreq = 0; if (referenceFreq > 2500) referenceFreq = 2500; break; default: break; } referenceFlow = referenceFreq / 2000.0; bool stopTest = false; if (cmd == Command.Start) { double pwFactor = 1.0; /// Increment reference flow meters for (int i = 0; i <= Config.Data.WMsCount; i++) { etPulses[i] += (int)referenceFreq; if (etPulses[i] > totalRefPulses) { pwFactor = 1.0 - (etPulses[i] - totalRefPulses) / referenceFreq; etPulses[i] = totalRefPulses; stopTest = true; } } /// Increment water meters double flowLtrPerSec = TestBenchSim.GetSimFlow() / 1800.0; for (int i = 1; i <= Config.Data.WMsCount; i++) { float wmPulsesPerLiter = 0; if ((BenchControl.Sequences.ProcessData.RegisterReaders[i - 1] != null) && (BenchControl.Sequences.ProcessData.BatchRslts.Batch.WaterMeters.Count >= i) && (BenchControl.Sequences.ProcessData.BatchRslts.Batch.WaterMeters[i - 1] != null)) { wmPulsesPerLiter = (float)BenchControl.Sequences.ProcessData.RegisterReaders[i-1].PulsesPerLtr; } wMeterPulsesF[i] += errFactor[i] * pwFactor * ((float)rand.Next(100) + 450.0f) * wmPulsesPerLiter * flowLtrPerSec; wMeterPulses[i] = (UInt16)wMeterPulsesF[i]; } if (etPulses[0] > totalRefPulses) { statusP |= StatusP.TestCompleted; statusP &= ~StatusP.TestInProgress; } } if (stopTest) { TestBenchSim.SetSimDiverter(false); statusP = (statusP | StatusP.TestCompleted); statusP = (statusP & ~StatusP.TestInProgress); } } StatusP lastStatusP; UInt128 lastRoute; public void RunDeviceAfter() { StatusP bufferedStatusP = StatusP; if (lastStatusP != bufferedStatusP) { string statusPStr = ((ulong)bufferedStatusP).ToString("x16"); log.InfoFormat("RunDeviceAfter() StatusP = {0}", statusPStr); Program.MainWnd.UpdateStatusP(statusPStr); lastStatusP = bufferedStatusP; } UInt128 bufferedRoute = simRoute; if (lastRoute != bufferedRoute) { string routeStr = bufferedRoute.ToString("x16"); log.InfoFormat("RunDeviceAfter() Route = {0}", routeStr); Program.MainWnd.UpdateRoute(routeStr); lastRoute = bufferedRoute; } } } }