/// /// Copyright (c) 2021 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using log4net; using Common; using Config.Entities; using Dirichlet.Numerics; using SchematicDrawing; using TBF.Rig.ControlBoard.Uni; using TBF.Rig.Generic; using TBF.Boxes; using TBF.Resources; namespace TBF.Rig.Uni.Diverter { public class Diverter : ComponentBase, IDevice, GenericDevices.IDiverter, GenericDevices.ISequenceCondition, GenericDevices.IHasCalendarEvents, IDrawingItCmpnt { private static readonly ILog log = LogManager.GetLogger(typeof(Diverter)); public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); } /// Configuration and wrappers readonly DiverterCfg divCfg; /// public int DiverterNr { get { return divCfg.DivNr1; } } /// 1-based public diverter number public int AdcNr { get { return divCfg.AdcNr; } } public int AdcValueToSink { get { return divCfg.AdcValueToSink; } } public int AdcValueToTank { get { return divCfg.AdcValueToTank; } } public IDrawingItem DrawingItem { get { return divCfg as IDrawingItem; } } /// public int StartThreshold { get { return Math.Max(0, Math.Min(1023, Convert.ToInt32(divCfg.AdcValueToSink + (divCfg.AdcValueToTank - divCfg.AdcValueToSink) * (divCfg.StartThresholdPct / 100.0)))); } } public int ThresholdLo { get { return Math.Max(0, Math.Min(1023, Convert.ToInt32(divCfg.AdcValueToSink + (divCfg.AdcValueToTank - divCfg.AdcValueToSink) * (divCfg.ThresholdLoPct / 100.0)))); } } public int ThresholdHi { get { return Math.Max(0, Math.Min(1023, Convert.ToInt32(divCfg.AdcValueToSink + (divCfg.AdcValueToTank - divCfg.AdcValueToSink) * (divCfg.ThresholdHiPct / 100.0)))); } } readonly UniCB uniCB; readonly UInt128 mask; /// derived from bitPosition in the constructor /// public bool State { get { return (uniCB.Route & mask) != 0; } } 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) { divCfg = cfg as DiverterCfg; uniCB = TbfComponents.FindComponent(cfg.ParentName, components) as UniCB; if (uniCB == null) throw new Exception("Cannot find " + Name + " parent"); if (divCfg.BitNr < 0 || divCfg.BitNr > 127) throw new ArgumentOutOfRangeException("position"); mask = (((UInt128)1) << divCfg.BitNr); log.Warn(this.ToString()); } public override void Initialize() { switchTimeStart = new FloatBox(divCfg.DfltSwithTimeStartMs / 1000.0f); switchTimeEnd = new FloatBox(divCfg.DfltSwithTimeEndMs / 1000.0f); diverterToTankOp = new SwitchDiverterOp(uniCB, DiverterNr, true); diverterToSinkOp = new SwitchDiverterOp(uniCB, DiverterNr, false); log.FatalFormat("{0} - Device successfully initialized", Name); } /// /// Calendar support /// public IList GetCalendarEvents() { DateTime calibrationDue = divCfg.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() { Int16 adcValue = uniCB.Data.AnalogInput[divCfg.AdcNr]; Handlers.OnAdcChanged(this, new CmdResponseArgs(CfgChangeCmd.GetAdc, divCfg.BitNr, 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) { switch (i) { case 0: return string.Format("{0} {1}", Name, Strings.Start); case 1: default: return string.Format("{0} {1}", Name, Strings.End); } } public IOperation ConditionOp(int i) { switch (i) { case 0: return diverterToTankOp; case 1: default: 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) { Int16 adcValue = uniCB.Data.AnalogInput[divCfg.AdcNr]; DiverterCfgCtrl.OnCmdResponse(this, new CmdResponseArgs(args.Command, divCfg.BitNr, adcValue)); } else if (args.Command == CfgChangeCmd.DivToTank) { uniCB.SwitchDiverter(true, divCfg.DivNr1, true); } else if (args.Command == CfgChangeCmd.DivToSink) { uniCB.SwitchDiverter(true, divCfg.DivNr1, false); } else if (args.Command == CfgChangeCmd.ReadDivTransition) { uniCB.GetDiverterTransitionData(true, this, this.State); } } }; } #endregion Configuration Change Handling } }