/// /// Copyright (c) 2013-2020 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using log4net; using Config.Entities; using Dirichlet.Numerics; using TBF.Rig.Generic; using TBF.Boxes; using TBF.Resources; namespace TBF.Rig.Elde.Diverter { public class Diverter : ComponentBase, IDevice, GenericDevices.IDiverter, GenericDevices.ISequenceCondition, GenericDevices.IHasCalendarEvents { private static readonly ILog log = LogManager.GetLogger(typeof(Diverter)); public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } readonly DiverterCfg diverterCfg; public int AdcNr { get { return diverterCfg.AdcNr; } } public int ThresholdGate { get { return diverterCfg.StartingLevel; } } public int ThresholdLo { get { return diverterCfg.ThresholdLo; } } public int ThresholdHi { get { return diverterCfg.ThresholdHi; } } readonly ControlBoardDev controlBoard; public bool State { get { return (controlBoard.RRoute & mask) != 0; } } /// /// Enumeration of balances via static fields and methods /// static int nextIdx = 0; public static int DivertersCount { get { return nextIdx; } } public static GenericDevices.IDiverter[] Diverters; /// int diverterNr0; /// 0-based diverter number assigned in Initialize() public int DiverterNr { get { return diverterNr0 + 1; } } /// 1-based public diverter number UInt128 mask; /// derived from bitPosition in the constructor int flowMtrNr4Cmd; IOperation diverterToTankOp; IOperation diverterToSinkOp; FloatBox switchTimeStart; FloatBox switchTimeEnd; public FloatBox SwitchTimeStart { get { return switchTimeStart; } } public FloatBox SwitchTimeEnd { get { return switchTimeEnd; } } /// /// For a given flow in [m3/h] returns a test time correction in [s] /// public double TestTimeCorrection(double flow) { return MeasurementCorrection.GetCorrection(flow, Corrections); } public Diverter() { } public Diverter(Generic.IComponentCfg cfg, IList components) : base(cfg) { diverterCfg = cfg as DiverterCfg; controlBoard = (ControlBoardDev)TbfComponents.FindComponent(cfg.ParentName, components); if (controlBoard == null) throw new Exception("Cannot find " + Name + " parent"); /// Prepare data for SendCalibData() control board component method if (diverterCfg.AdcNr >= 0 && diverterCfg.AdcNr < controlBoard.RegValveCalib.GetLength(0)) { controlBoard.RegValveCalib[diverterCfg.AdcNr, 0] = (uint)diverterCfg.AdcValueToSink; controlBoard.RegValveCalib[diverterCfg.AdcNr, 1] = (uint)diverterCfg.AdcValueToTank; diverterNr0 = nextIdx++; /// if (Diverters == null || Diverters.Length < nextIdx) { GenericDevices.IDiverter[] divertersSoFar = Diverters; Diverters = new GenericDevices.IDiverter[nextIdx]; if (divertersSoFar != null) { for (int i = 0; i < divertersSoFar.Length; i++) Diverters[i] = divertersSoFar[i]; } Diverters[nextIdx - 1] = this; } } else { log.ErrorFormat("Unable to set {0} ADC levels: RegValveCalib array size={1}, diverter AdcNr={2}", Name, controlBoard.RegValveCalib.GetLength(0), diverterCfg.AdcNr); } } public override void Initialize() { if (diverterCfg.BitPosition < 0 || diverterCfg.BitPosition >= 127) throw new ArgumentOutOfRangeException("position"); mask = (((UInt128)1) << diverterCfg.BitPosition); switchTimeStart = new FloatBox(diverterCfg.DfltSwithTimeStartMs / 1000.0f); switchTimeEnd = new FloatBox(diverterCfg.DfltSwithTimeEndMs / 1000.0f); int divNrFromName; if (!int.TryParse(Name.Substring(3), out divNrFromName)) { divNrFromName = nextIdx; } #if FUZHOU_50 || FUZHOU_150 || FUZHOU_300 || GENESIS || PETERSBURG_50 || PETERSBURG_200 || ROMA_200 || SLM_150 flowMtrNr4Cmd = divNrFromName + 1; #elif BADGER_STREDNA_TRAT flowMtrNr4Cmd = (divNrFromName == 1) ? 1 : ((divNrFromName == 2) ? 9 : 20); #elif BADGER_VELKA_TRAT flowMtrNr4Cmd = ((divNrFromName % 10) == 1) ? 0x11 : (((divNrFromName % 10) == 2) ? 0x22 : 0x33); #elif CEVAK_200 flowMtrNr4Cmd = (divNrFromName == 4) ? 5 : divNrFromName; #elif DEWA_300 || PUCHONG_200 flowMtrNr4Cmd = divNrFromName + 2; /// Div1: 1,2,3, Div2: 4, Div3: 5, Div4: 6, Div5: 7 #elif FILIPINY_50 flowMtrNr4Cmd = (divNrFromName == 1) ? 1 : 7; #elif FUZHOU_100 flowMtrNr4Cmd = divNrFromName; #elif GELSENWASSER switch (divNrFromName) { default: case 1: flowMtrNr4Cmd = 1; break; case 2: flowMtrNr4Cmd = 0x12; break; case 3: flowMtrNr4Cmd = 3; break; case 4: flowMtrNr4Cmd = 5; break; } #elif TURA_IPERL || TURA_IPERL_NEW flowMtrNr4Cmd = divNrFromName + 16 * divNrFromName; #elif MILWAUKEE flowMtrNr4Cmd = (divNrFromName == 1) ? 1 : 68; #else /// all other benches flowMtrNr4Cmd = (divNrFromName == 1) ? 1 : 3; #endif diverterToTankOp = new SwitchDiverterOp(controlBoard, true, flowMtrNr4Cmd); diverterToSinkOp = new SwitchDiverterOp(controlBoard, false, flowMtrNr4Cmd); log.FatalFormat("{0} initialized: {1}", Name, this); } /// /// Calendar support /// public IList GetCalendarEvents() { DateTime calibrationDue = diverterCfg.CalibValidDate; IList calendarEvents = new List(); if (calibrationDue > TBF.UI.Constants.MinDate) { /// Calibration due date calendar event calendarEvents.Add(new TBF.UI.Calendar.CalibrationDueDateEvent(calibrationDue.Date, Name, string.Format(Strings.Calibration_due_date_is_0, calibrationDue.Date.ToString(TBF.UI.Constants.DateFormat)))); if (DateTime.Now.Date <= calibrationDue.AddDays(-7)) { /// Weekly reminders (last 5 weeks) calendarEvents.Add(new TBF.UI.Calendar.CalibrationReminderEvent(calibrationDue.Date.AddDays(-35), Name, string.Format(Strings.Calibration_due_date_is_0, calibrationDue.Date.ToString(TBF.UI.Constants.DateFormat)), false)); } if (DateTime.Now.Date <= calibrationDue.Date) { /// Daily reminders (last 5 days) calendarEvents.Add(new TBF.UI.Calendar.CalibrationReminderEvent(calibrationDue.AddDays(-5), Name, string.Format(Strings.Calibration_due_date_is_0, calibrationDue.Date.ToString(TBF.UI.Constants.DateFormat)), true)); } } return calendarEvents; } /// /// IDevice interface implementation /// public void RunDeviceBefore() { int adcValue = (int)StateMachine.ControlBoard.AnalogInputRaw(diverterCfg.AdcNr, 0); Handlers.OnAdcChanged(this, new CmdResponseArgs(CfgChangeCmd.GetAdc, diverterCfg.BitPosition, adcValue)); } public void RunDeviceAfter() { } public void StopDevice() { } public void StopDevice2() { } /// /// ISequenceCondition interface implementation /// public int ConditionsCount { get { return 2; } } /// Returned strings are added to the combo-box public string ConditionName(int i) { if (i == 0) return string.Format("{0} {1}", Name, Strings.Start); else return string.Format("{0} {1}", Name, Strings.End); } public IOperation ConditionOp(int i) { if (i == 0) return diverterToTankOp; else return diverterToSinkOp; } #region Configuration Change Handling public static void OnCfgChange(object sender, CfgChangeArgs args) { if (CfgChangeHandler == null) return; try { CfgChangeHandler(sender, args); } catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); } } public static event EventHandler CfgChangeHandler; public override void StartChangeHandler() { CfgChangeHandler += delegate(object sender, CfgChangeArgs args) { DiverterCfg tmpcfg = args.Cfg as DiverterCfg; if (tmpcfg != null && tmpcfg.Name.Equals(Name)) { if (args.Command == CfgChangeCmd.CfgChange) { } else if (args.Command == CfgChangeCmd.GetAdc1 || args.Command == CfgChangeCmd.GetAdc2) { int adcValue = (int)controlBoard.AnalogInputRaw(diverterCfg.AdcNr, 0); DiverterCfgCtrl.OnCmdResponse(this, new CmdResponseArgs(args.Command, diverterCfg.BitPosition, adcValue)); } else if (args.Command == CfgChangeCmd.DivToTank) { controlBoard.DiverterToTank(flowMtrNr4Cmd); } else if (args.Command == CfgChangeCmd.DivToSink) { controlBoard.DiverterToSink(flowMtrNr4Cmd); } else if (args.Command == CfgChangeCmd.ReadDivTransition) { controlBoard.ReadDiverterTransition(flowMtrNr4Cmd); } } }; } #endregion Configuration Change Handling } }