/// /// Copyright (c) 2021 Sensus Slovensko a.s. /// using System; using log4net; using TBF.Rig.Sequences; using TBF.Rig.Uni.Diverter; namespace TBF.Rig.ControlBoard.Uni { public class DivTransitionData { private static readonly ILog log = LogManager.GetLogger(typeof(DivTransitionData)); /// Used in FrameFitsData(), etc. public const int MessageLen = 255; public const byte MessageCode = (byte)'K'; /// Associated diverter and plotter public static Diverter Diverter; public static bool ToTank; public static Statistics Plotter; public static int DiverterAssociationValidUntil; /// Diverter transition data public byte[] Samples; public int Resolution_ms; public int TransitionTime_ms; const int SamplesCount = 247; DivTransitionData() { Samples = new byte[SamplesCount]; Resolution_ms = Const.DivTimeResolution; } /// /// Returns tru when receive data fit the message frame /// /// Received data /// Cumulative sums of received data bytes /// Received bytes count /// Offset of the message /// true when frame fits data public static bool FrameFitsData(byte[] rcvdData, int[] cumulativeSums, int rcvdBytesCount, int offset) { if (offset + MessageLen > rcvdBytesCount) return false; int checksum = cumulativeSums[offset + MessageLen - 3] - cumulativeSums[offset]; return rcvdData[offset] == Const.STX && rcvdData[offset + 1] == 0x01 && rcvdData[offset + 2] == ((MessageLen - 5) & 0xFF) && rcvdData[offset + 3] == MessageCode && rcvdData[offset + MessageLen - 2] == (checksum & 0xFF) && rcvdData[offset + MessageLen - 1] == ((checksum >> 8) & 0xFF); } /// /// Proces received data /// /// Received data /// Offset of the message public static DivTransitionData GetData(byte[] rcvdData, int offset) { log.DebugFormat("DivTransitionDataGetData() ... Diverter = {0}, DiverterAssociationValidUntil-StateMachine.Time = {1}s left", (Diverter != null) ? Diverter.Name : "none", DiverterAssociationValidUntil - StateMachine.Time); var data = new DivTransitionData(); for (int i = 0; i < SamplesCount; i++) { data.Samples[i] = rcvdData[offset + 6 + i]; } if (Diverter != null && StateMachine.Time <= DiverterAssociationValidUntil) { data.TransitionTime_ms = Const.DivTimeResolution * CalculateDivTransitionTime(data.Samples, Diverter.ThresholdLo, Diverter.ThresholdHi); log.InfoFormat("{0} transition time = {1} ms", Diverter.Name, data.TransitionTime_ms); if (ToTank) { if (Diverter != null && Diverter.SwitchTimeStart != null) Diverter.SwitchTimeStart.Val = data.TransitionTime_ms / 1000.0f; } else { if (Diverter != null && Diverter.SwitchTimeEnd != null) Diverter.SwitchTimeEnd.Val = data.TransitionTime_ms / 1000.0f; } if (Plotter != null) { int rangeLo = Math.Min(Diverter.AdcValueToSink, Diverter.AdcValueToTank); int rangeHi = Math.Max(Diverter.AdcValueToSink, Diverter.AdcValueToTank); if (rangeLo != rangeHi) { float denominator = Convert.ToSingle(rangeHi - rangeLo); for (int i = 0; i < SamplesCount; i++) { float y = Convert.ToSingle(data.Samples[i] - rangeLo) / denominator; Plotter.Update(y); } } Plotter.Stop(); } } return data; } /// /// Analyze diverter transition data and calculate transition time /// /// Raw data samples /// Threshod level Low /// Threshold level High /// Transition time in sasmple periods static int CalculateDivTransitionTime(byte[] samples, int thresholdLo, int thresholdHi) { bool startedRising = false; bool startedFalling = false; bool stopped = false; int transitionStartIdx = 0; int transitionEndIdx = 0; int level = 4*samples[0]; for (int i = 1; i < SamplesCount; i++) { if (!startedRising && !startedFalling) { if (level <= thresholdLo && 4*samples[i] > thresholdLo) { transitionStartIdx = i; startedRising = true; } else if (level >= thresholdHi && 4*samples[i] < thresholdHi) { transitionStartIdx = i; startedFalling = true; } } else if (startedRising && !stopped && level < thresholdHi && 4*samples[i] >= thresholdHi) { transitionEndIdx = i; stopped = true; break; } else if (startedFalling && !stopped && level > thresholdLo && 4*samples[i] <= thresholdLo) { transitionEndIdx = i; stopped = true; break; } } log.DebugFormat("CalculateDivTransitionTime() ... thresholdLo={0} thresholdHi={1} startIx={2} endIx={3} time = {4} ms", thresholdLo, thresholdHi, transitionStartIdx, transitionEndIdx, 2 * (transitionEndIdx - transitionStartIdx)); return transitionEndIdx - transitionStartIdx; } } }