tbf/TestBenchFramework/BenchControl/Elde/Valve/SetValvesOp.cs

223 lines
7.6 KiB
C#

using System;
using System.Collections.Generic;
using log4net;
using TBF.BenchControl.GenericDevices;
namespace TBF.BenchControl.Elde.Valve
{
public class SetValvesOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(SetValvesOp));
/// Set by the constructor
ControlBoardDev controlBoard;
class SwitchPoint
{
public int TimeSec; /// Relative time in [s] from the start of the operation
public IList<IValve> VOpen; /// List of valves to open in this point of time
public IList<IValve> VClose; /// List of valves to close in this point of time
public ulong MasksOpen; /// OR-ed bitmasks of valves to open in this point of time
public ulong MasksClose; /// OR-ed bitmasks of valves to close in this point of time
public SwitchPoint(int time, IList<IValve> vOpen, IList<IValve> vClose)
{
this.TimeSec = time;
this.VOpen = (vOpen == null) ? new List<IValve>() : vOpen;
this.VClose = (vClose == null) ? new List<IValve>() : vClose;
}
/// Max. delay in [s] of all valves to be opened or closed
public int MaxDelay
{
get
{
int max = 0;
foreach (var vlv in VOpen) if ((vlv != null) && (vlv.Delay > max)) max = vlv.Delay;
foreach (var vlv in VClose) if ((vlv != null) && (vlv.Delay > max)) max = vlv.Delay;
return max;
}
}
}
IList<SwitchPoint> switchPointsRaw;
IList<SwitchPoint> switchPoints;
int nextIx;
int swStartTime;
int maxDelayTime; /// Max. delay from all valve/pump switches.
/// Relative time in [s] from the start of the operation
/// <summary>
/// Processes coupled valves and creates switch points.
/// </summary>
/// <param name="valvesOpen">A list of opening master valves</param>
/// <param name="valvesClose">A list of closing master valves</param>
/// <returns></returns>
IList<SwitchPoint> CollectSwitchPoints(IList<IValve> valvesOpen, IList<IValve> valvesClose)
{
IList<SwitchPoint> result = new List<SwitchPoint>();
result.Add(new SwitchPoint(0, valvesOpen, valvesClose));
foreach (var valve in StateMachine.CoupledValves)
{
if ((!valve.InvertCouple && valvesOpen.Contains(valve.CoupledTo)) ||
(valve.InvertCouple && valvesClose.Contains(valve.CoupledTo)))
{
/// The coupled valve 'valve' is opening
int time = valve.LagOpening;
if (time == 0)
{
result[0].VOpen.Add(valve);
}
else
{
result.Add(new SwitchPoint(time, ValveBase.MakeList(valve), null));
}
}
else if ((!valve.InvertCouple && valvesClose.Contains(valve.CoupledTo)) ||
(valve.InvertCouple && valvesOpen.Contains(valve.CoupledTo)))
{
/// The coupled valve 'valve' is closing
int time = valve.LagClosing;
if (time == 0)
{
result[0].VClose.Add(valve);
}
else
{
result.Add(new SwitchPoint(time, null, ValveBase.MakeList(valve)));
}
}
}
return result;
}
IList<SwitchPoint> SortAndMergeSwitchPoints(IList<SwitchPoint> unsorted)
{
IList<SwitchPoint> result = new List<SwitchPoint>();
SwitchPoint lastAdded = null;
while (unsorted.Count > 0)
{
SwitchPoint first = null;
foreach (var point in unsorted)
{
if (first == null || first.TimeSec > point.TimeSec) first = point;
}
if (lastAdded == null || lastAdded.TimeSec != first.TimeSec)
{
result.Add(first);
lastAdded = first;
}
else
{
lastAdded.VOpen = ValveBase.Merge(lastAdded.VOpen, first.VOpen);
lastAdded.VClose = ValveBase.Merge(lastAdded.VClose, first.VClose);
}
unsorted.Remove(first);
}
return result;
}
void MakeMasks(IList<SwitchPoint> switchPoints, int timeShift)
{
foreach (var point in switchPoints)
{
/// Only Elde.Valve valves are used, other valves are ignored
point.MasksOpen = 0;
foreach (var valve in point.VOpen)
{
if (valve is Valve) point.MasksOpen |= (valve as Valve).Mask;
if (valve is Pump.Pump) point.MasksOpen |= (valve as Pump.Pump).Mask;
if (valve is PumpWithFM.Pump) point.MasksOpen |= (valve as PumpWithFM.Pump).Mask;
}
point.MasksClose = 0;
foreach (var valve in point.VClose)
{
if (valve is Valve) point.MasksClose |= (valve as Valve).Mask;
if (valve is Pump.Pump) point.MasksClose |= (valve as Pump.Pump).Mask;
if (valve is PumpWithFM.Pump) point.MasksClose |= (valve as PumpWithFM.Pump).Mask;
}
point.TimeSec += timeShift;
}
}
/// <summary>
/// Open and/or close multiple valves.
/// Events: ValvesSet
/// </summary>
/// <param name="controlBoard">Control board device</param>
/// <param name="valvesOpen">A list of opening master valves</param>
/// <param name="valvesClose">A list of closing master valves</param>
/// <remarks>Only Elde.Valve valves are used, other valves on the lists are ignored</remarks>
public SetValvesOp(ControlBoardDev controlBoard, IList<IValve> valvesOpen, IList<IValve> valvesClose)
{
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
this.controlBoard = controlBoard;
if (valvesOpen == null) valvesOpen = new List<IValve>();
if (valvesClose == null) valvesOpen = new List<IValve>();
switchPointsRaw = CollectSwitchPoints(valvesOpen, valvesClose);
switchPoints = SortAndMergeSwitchPoints(switchPointsRaw);
int timeShift = -switchPoints[0].TimeSec;
MakeMasks(switchPoints, timeShift);
}
/// <summary>
/// Open one valve and/or close one valve.
/// Events: ValvesSet
/// </summary>
/// <param name="controlBoard">Control board device</param>
/// <param name="valveOpen">Valve to be opened</param>
/// <param name="valveClose">Valve to be closed</param>
/// <remarks>Only Elde.Valve valves are used, other valves on the lists are ignored</remarks>
public SetValvesOp(ControlBoardDev controlBoard, IValve valveOpen, IValve valveClose)
: this(controlBoard, ValveBase.MakeList(valveOpen), ValveBase.MakeList(valveClose))
{
}
/// <summary>Start this operation</summary>
public void Start()
{
controlBoard.SetValves(switchPoints[0].MasksOpen, switchPoints[0].MasksClose);
swStartTime = StateMachine.Time;
maxDelayTime = switchPoints[0].MaxDelay;
nextIx = 1;
}
/// <summary>Run this operation</summary>
/// <returns>
/// Event.SetValvesDone
/// </returns>
public Event Run()
{
if (nextIx >= switchPoints.Count)
{
if (StateMachine.Time >= swStartTime + maxDelayTime) return Event.ValvesSet;
else return Event.None;
}
if (StateMachine.Time >= swStartTime + switchPoints[nextIx].TimeSec)
{
if (switchPoints[nextIx].TimeSec + switchPoints[nextIx].MaxDelay > maxDelayTime)
{
maxDelayTime = switchPoints[nextIx].TimeSec + switchPoints[nextIx].MaxDelay;
}
controlBoard.SetValves(switchPoints[nextIx].MasksOpen, switchPoints[nextIx].MasksClose);
nextIx++;
}
return Event.None;
}
/// <summary>Start this operation</summary>
public void Stop()
{
}
}
}