Files
tbf/TBF/Rig/ControlBoard/Uni/Action.cs
T

448 lines
18 KiB
C#

///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using Dirichlet.Numerics;
namespace TBF.Rig.ControlBoard.Uni
{
public enum ActionID
{
/// Basic
ChangeRoute = 1, /// Change digital outputs (route)
MeasureFlow = 2, /// Activate a flow meter to measure the flow
SetFlow = 4, /// Set flow
StartTest = 8, /// Start a test
StopTest = 0x10, /// Stop a test or a flow regulation
RegVlvIncrMove = 0x20,
RegVlvMoveToPos = 0x40,
RegVlvStop = 0x80,
SwitchDiverter = 0x100, /// Switch diverter to tank/sink
/// Advanced
GetDiverterTransitionData,
GetScopeAnalyzerData,
ResetScopeAnalyzer,
GetSwitchCounterData,
}
public class Action
{
private static readonly ILog log = LogManager.GetLogger(typeof(Action));
public ActionID ActionId { get; set; }
public ulong Route { get; set; } /// ChangeRoute argument
public int FlowMId { get; set; } /// MeasureFlow, SetFlow and StartTest argument
public int RegVId { get; set; } /// SetFlow and StartTest argument
public int DivId { get; set; } /// StartTest and SwitchDiverter argument
public Command StartStop { get; set; } /// MeasureFlow, SetFlow, StartTest, StopTest and SwitchDiverter
public bool IsSyncMethod { get; set; } /// StartTest argument
public bool IsDivUsed { get; set; } /// StartTest argument
public bool ToTank { get; set; } /// SwitchDiverter argument
public int TotalPulsesCount { get; set; } /// StartTest argument
public int MassPulsesCount { get; set; } /// StartTest argument
public RegValveMode RegVMode { get; set; } /// SetFlow, RegVlvIncrMove, RegVlvMoveToPos, RegVlvStop
public int RVMovePar1 { get; set; } /// SetFlow, RegVlvIncrMove, RegVlvMoveToPos
public int RVMovePar2 { get; set; } /// SetFlow, RegVlvIncrMove, RegVlvMoveToPos
public int PID { get; set; } /// SetFlow
public int TolerRV { get; set; } /// SetFlow
public int StabTime { get; set; } /// SetFlow
public int DivThreshold { get; set; } /// StartTest argument
public Action()
{
/// Values -1 indicate the related arguments are not used yet
FlowMId = -1;
RegVId = -1;
DivId = -1;
StartStop = Command.None;
RegVMode = RegValveMode.None;
/// These values are used by one action type only. No conflicts possible
Route = 0;
IsSyncMethod = false;
IsDivUsed = false;
TotalPulsesCount = 0;
MassPulsesCount = 0;
RVMovePar1 = 0;
RVMovePar2 = 0;
}
public bool IsStart()
{
return StartStop == Command.Start;
}
public bool IsStop()
{
return StartStop == Command.Stop;
}
///----------------------------------------------------------------------------------------------
public static Action ChangeRoute(ulong route)
{
return new Action
{
ActionId = ActionID.ChangeRoute,
Route = route,
};
}
void SetChangeRouteArgs(Action action)
{
Route = action.Route;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedChangeRouteArgs(Action newAction)
{
return Route == newAction.Route;
}
///----------------------------------------------------------------------------------------------
public static Action MeasureFlow(int flowMeterId)
{
return new Action
{
ActionId = ActionID.MeasureFlow,
FlowMId = flowMeterId,
StartStop = Command.Start,
};
}
void SetMeasureFlowArgs(Action action)
{
FlowMId = action.FlowMId;
StartStop = Command.Start;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedMeasureFlowArgs(Action newAction)
{
return (FlowMId == -1 || FlowMId == newAction.FlowMId) &&
(StartStop == Command.None || StartStop == Command.Start);
}
///----------------------------------------------------------------------------------------------
public static Action SetFlow(int flowMeterId, int regValveId, double freqLo, double freqHi,
int pid, int tolerRV, int stabTime)
{
int rvMovePar1 = Convert.ToInt32(Math.Round(13.1072 * freqLo));
int rvMovePar2 = Convert.ToInt32(Math.Round(13.1072 * freqHi));
return new Action
{
ActionId = ActionID.SetFlow,
FlowMId = flowMeterId,
RegVId = regValveId,
RegVMode = RegValveMode.TargetFrequency,
RVMovePar1 = rvMovePar1,
RVMovePar2 = rvMovePar2,
PID = pid,
TolerRV = tolerRV,
StabTime = stabTime,
StartStop = Command.Start,
};
}
void SetSetFlowArgs(Action action)
{
FlowMId = action.FlowMId;
RegVId = action.RegVId;
RegVMode = action.RegVMode;
RVMovePar1 = action.RVMovePar1;
RVMovePar2 = action.RVMovePar2;
PID = action.PID;
TolerRV = action.TolerRV;
StabTime = action.StabTime;
StartStop = Command.Start;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedSetFlowArgs(Action newAction)
{
return (FlowMId == -1 || FlowMId == newAction.FlowMId) &&
(RegVId == -1 || RegVId == newAction.RegVId) &&
(RegVMode == RegValveMode.None || RegVMode == newAction.RegVMode) &&
(RVMovePar1 == -1 || RVMovePar1 == newAction.RVMovePar1) &&
(RVMovePar2 == -1 || RVMovePar2 == newAction.RVMovePar2) &&
(StartStop == Command.None || StartStop == Command.Start);
}
///----------------------------------------------------------------------------------------------
public static Action StartTest(int flowMId, int divId, int divThreshold, bool isSyncMethod,
bool isDivUsed, int totalPulsesCount, int massPulsesCount = -1)
{
return new Action
{
ActionId = ActionID.StartTest,
FlowMId = flowMId,
DivId = divId,
DivThreshold = divThreshold,
IsSyncMethod = isSyncMethod,
IsDivUsed = isDivUsed,
TotalPulsesCount = totalPulsesCount,
MassPulsesCount = (massPulsesCount == -1) ? totalPulsesCount : massPulsesCount,
StartStop = Command.Start,
};
}
void SetStartTestArgs(Action action)
{
FlowMId = action.FlowMId;
DivId = action.DivId;
DivThreshold = action.DivThreshold;
IsSyncMethod = action.IsSyncMethod;
IsDivUsed = action.IsDivUsed;
TotalPulsesCount = action.TotalPulsesCount;
MassPulsesCount = action.MassPulsesCount;
StartStop = Command.Start;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedStartTestArgs(Action newAction)
{
return (FlowMId == -1 || FlowMId == newAction.FlowMId) &&
(DivId == -1 || DivId == newAction.DivId) &&
(StartStop == Command.None || StartStop == Command.Start);
}
///----------------------------------------------------------------------------------------------
public static Action StopTest()
{
return new Action()
{
ActionId = ActionID.StopTest,
StartStop = Command.Stop,
};
}
void SetStopTestArgs(Action action)
{
StartStop = Command.Stop;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedStopTestArgs(Action action)
{
return (StartStop == Command.None || StartStop == Command.Stop);
}
///----------------------------------------------------------------------------------------------
public static Action RegVlvIncrMove(int regValveId, double timeSec)
{
int rvMovePar = Math.Abs(Convert.ToInt32(Math.Round(timeSec / 0.050))); /// Step is 50 ms
return new Action
{
ActionId = ActionID.RegVlvIncrMove,
RegVId = regValveId,
RegVMode = (timeSec >= 0) ? RegValveMode.PulseWidth : (RegValveMode.PulseWidth | RegValveMode.NegPulseWidth),
RVMovePar1 = rvMovePar,
RVMovePar2 = rvMovePar,
};
}
void SetRegVlvIncrMoveArgs(Action action)
{
RegVId = action.RegVId;
RegVMode = action.RegVMode;
RVMovePar1 = action.RVMovePar1;
RVMovePar2 = action.RVMovePar2;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedRegVlvIncrMoveArgs(Action newAction)
{
return (RegVId == -1 || RegVId == newAction.RegVId) &&
(RegVMode == RegValveMode.None || RegVMode == newAction.RegVMode);
}
///----------------------------------------------------------------------------------------------
public static Action RegVlvMoveToPos(int regValveId, double positionLo, double positionHi = -1)
{
int rvMovePar1, rvMovePar2; /// TODO
///
if (positionHi < 0)
{
/// Center position specified, calculate a range
rvMovePar1 = 0; // TODO
rvMovePar2 = 0; // TODO
}
else
{
/// Lower and upper range of position specified
rvMovePar1 = 0; // TODO
rvMovePar2 = 0; // TODO
}
return new Action
{
ActionId = ActionID.RegVlvMoveToPos,
RegVId = regValveId,
RegVMode = RegValveMode.TargetPosition,
RVMovePar1 = rvMovePar1,
RVMovePar2 = rvMovePar2,
};
}
void SetRegVlvMoveToPosArgs(Action action)
{
RegVId = action.RegVId;
RegVMode = action.RegVMode;
RVMovePar1 = action.RVMovePar1;
RVMovePar2 = action.RVMovePar2;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedRegVlvMoveToPosArgs(Action newAction)
{
return (RegVId == -1 || RegVId == newAction.RegVId) &&
(RegVMode == RegValveMode.None || RegVMode == newAction.RegVMode);
}
///----------------------------------------------------------------------------------------------
public static Action RegVlvStop(int regValveId)
{
return new Action
{
ActionId = ActionID.RegVlvStop,
RegVId = regValveId,
RegVMode = RegValveMode.Stop,
RVMovePar1 = 0,
RVMovePar2 = 0,
};
}
void SetRegVlvStopArgs(Action action)
{
RegVId = action.RegVId;
RegVMode = action.RegVMode;
RVMovePar1 = action.RVMovePar1;
RVMovePar2 = action.RVMovePar2;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedRegVlvStopArgs(Action newAction)
{
return (RegVId == -1 || RegVId == newAction.RegVId) &&
(RegVMode == RegValveMode.None || RegVMode == newAction.RegVMode);
}
///----------------------------------------------------------------------------------------------
public static Action SwitchDiverter(int divId, bool toTank)
{
return new Action
{
ActionId = ActionID.SwitchDiverter,
DivId = divId,
ToTank = toTank,
StartStop = Command.Start,
};
}
void SetSwitchDiverterArgs(Action action)
{
DivId = action.DivId;
ToTank = action.ToTank;
StartStop = Command.Start;
}
/// Check whether new action arguments are compatible with alredy collected arguments (true = yes)
bool CheckSharedSwitchDiverterArgs(Action action)
{
return (DivId == -1 || DivId == action.DivId) ||
(StartStop == Command.None || StartStop == Command.Start);
}
///----------------------------------------------------------------------------------------------
void SetArgs(Action action)
{
ActionId |= action.ActionId;
switch (action.ActionId)
{
case ActionID.ChangeRoute: SetChangeRouteArgs(action); return;
case ActionID.MeasureFlow: SetMeasureFlowArgs(action); return;
case ActionID.SetFlow: SetSetFlowArgs(action); return;
case ActionID.StartTest: SetStartTestArgs(action); return;
case ActionID.StopTest: SetStopTestArgs(action); return;
case ActionID.RegVlvIncrMove: SetRegVlvIncrMoveArgs(action); return;
case ActionID.RegVlvMoveToPos: SetRegVlvMoveToPosArgs(action); return;
case ActionID.RegVlvStop: SetRegVlvStopArgs(action); return;
case ActionID.SwitchDiverter: SetSwitchDiverterArgs(action); return;
default: return;
}
}
/// <summary>
/// Check whether new action arguments are compatible with alredy collected arguments
/// </summary>
/// <param name="action">Action to be executed together with already collected actions</param>
/// <returns>true when compatible</returns>
bool CheckSharedArgs(Action action)
{
switch (action.ActionId)
{
case ActionID.ChangeRoute: return CheckSharedChangeRouteArgs(action);
case ActionID.MeasureFlow: return CheckSharedMeasureFlowArgs(action);
case ActionID.SetFlow: return CheckSharedSetFlowArgs(action);
case ActionID.StartTest: return CheckSharedStartTestArgs(action);
case ActionID.StopTest: return CheckSharedStopTestArgs(action);
case ActionID.RegVlvIncrMove: return CheckSharedRegVlvIncrMoveArgs(action);
case ActionID.RegVlvMoveToPos: return CheckSharedRegVlvMoveToPosArgs(action);
case ActionID.RegVlvStop: return CheckSharedRegVlvStopArgs(action);
case ActionID.SwitchDiverter: return CheckSharedSwitchDiverterArgs(action);
default: return false;
}
}
///----------------------------------------------------------------------------------------------
public static Action FetchNonConflictingActions(Queue<Action> queue)
{
log.Debug("Fetching non conflicting actions:");
if (queue == null || queue.Count == 0) return null;
Action resultA = queue.Dequeue();
log.Debug(resultA.ToString());
while (queue.Count > 0)
{
var peekA = queue.Peek();
if ((resultA.ActionId & peekA.ActionId) == 0 && resultA.CheckSharedArgs(peekA) == true)
{
/// ActionId would not be repeated and arguments are compatible => apply the new action
resultA.SetArgs(peekA);
log.Debug(peekA.ToString());
queue.Dequeue();
}
else
{
/// Leave actions in the queue and quit the loop as the next scheduled action is incompatible
break;
}
}
return resultA;
}
public override string ToString()
{
string args;
switch (ActionId)
{
case ActionID.ChangeRoute:
args = string.Format("Route={0}", Route.ToString("X16"));
break;
case ActionID.MeasureFlow:
args = string.Format("Etalon={0}", FlowMId);
break;
case ActionID.SetFlow:
args = string.Format("Etalon={0} RV={1} Par1={2} Par2={3}", FlowMId, RegVId, RVMovePar1, RVMovePar2);
break;
case ActionID.StartTest:
args = string.Format("Etalon={0} TotalP={1} MassP={2}", FlowMId, TotalPulsesCount, MassPulsesCount);
break;
case ActionID.RegVlvIncrMove:
args = string.Format("Time={0}ms", (RegVMode & RegValveMode.NegPulseWidth) != 0 ? -50 * RVMovePar1 : 50 * RVMovePar1);
break;
case ActionID.RegVlvMoveToPos:
args = string.Format("Position={0}%", 0); /// TODO
break;
default:
args = string.Empty;
break;
}
return string.Format(" {0} {1}", ActionId, args);
}
}
}