313 lines
12 KiB
C#
313 lines
12 KiB
C#
///
|
|
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
|
///
|
|
using System.Collections.Generic;
|
|
using log4net;
|
|
using Dirichlet.Numerics;
|
|
|
|
namespace TBF.BenchControl.ControlBoard.Uni
|
|
{
|
|
public enum ActionID
|
|
{
|
|
/// Basic
|
|
ChangeRoute = 1, /// Change digital outputs (route)
|
|
SetFlow = 2, /// Set flow
|
|
MeasureFlow = 4, /// Activate a flow meter to measure the flow
|
|
StartTest = 8, /// Start a test
|
|
Stop = 16, /// Stop a test or a flow regulation
|
|
SwitchDiverter = 32, /// 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; } /// SetFlow, MeasureFlow and StartTest argument
|
|
public int RegVId { get; set; } /// SetFlow and StartTest argument
|
|
public int DivId { get; set; } /// StartTest and SwitchDiverter argument
|
|
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 int FlowRegP1 { get; set; } /// SetFlow
|
|
public int FlowRegP2 { get; set; } /// SetFlow
|
|
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
|
|
int StartStop { get; set; } /// Implicitly used by SetFlow, StartTest and Stop: -1=not defined, 0=stop, 1=start
|
|
|
|
|
|
public Action()
|
|
{
|
|
/// Values -1 indicate the related arguments are not used yet
|
|
FlowMId = -1;
|
|
RegVId = -1;
|
|
DivId = -1;
|
|
StartStop = -1;
|
|
|
|
/// These values are used by one action type only. No conflicts possible
|
|
Route = 0;
|
|
FlowRegP1 = 0;
|
|
FlowRegP2 = 0;
|
|
TotalPulsesCount = 0;
|
|
MassPulsesCount = 0;
|
|
}
|
|
|
|
|
|
public bool IsStart()
|
|
{
|
|
return (ActionId & (ActionID.SetFlow | ActionID.StartTest)) != 0;
|
|
}
|
|
|
|
public bool IsStop()
|
|
{
|
|
return (ActionId & ActionID.Stop) != 0;
|
|
}
|
|
|
|
///----------------------------------------------------------------------------------------------
|
|
public static Action ChangeRoute(ulong route)
|
|
{
|
|
return new Action
|
|
{
|
|
ActionId = ActionID.ChangeRoute,
|
|
Route = route,
|
|
};
|
|
}
|
|
void SetChangeRouteArgs(Action action)
|
|
{
|
|
Route = action.Route;
|
|
}
|
|
bool CompareChangeRouteArgs(Action action)
|
|
{
|
|
return Route == action.Route;
|
|
}
|
|
|
|
///----------------------------------------------------------------------------------------------
|
|
public static Action MeasureFlow(int flowMeterId)
|
|
{
|
|
return new Action
|
|
{
|
|
ActionId = ActionID.MeasureFlow,
|
|
FlowMId = flowMeterId,
|
|
};
|
|
}
|
|
void SetMeasureFlowArgs(Action action)
|
|
{
|
|
FlowMId = action.FlowMId;
|
|
}
|
|
bool CompareMeasureFlowArgs(Action action)
|
|
{
|
|
return (FlowMId == -1 || FlowMId == action.FlowMId);
|
|
}
|
|
|
|
///----------------------------------------------------------------------------------------------
|
|
public static Action SetFlow(int flowMeterId, int regValveId, int flowRegPar1, int flowRegPar2,
|
|
int pid, int tolerRV, int stabTime)
|
|
{
|
|
return new Action
|
|
{
|
|
ActionId = ActionID.SetFlow,
|
|
FlowMId = flowMeterId,
|
|
RegVId = regValveId,
|
|
FlowRegP1 = flowRegPar1,
|
|
FlowRegP2 = flowRegPar2,
|
|
PID = pid,
|
|
TolerRV = tolerRV,
|
|
StabTime = stabTime,
|
|
StartStop = 1,
|
|
};
|
|
}
|
|
void SetSetFlowArgs(Action action)
|
|
{
|
|
FlowMId = action.FlowMId;
|
|
RegVId = action.RegVId;
|
|
FlowRegP1 = action.FlowRegP1;
|
|
FlowRegP2 = action.FlowRegP2;
|
|
PID = action.PID;
|
|
TolerRV = action.TolerRV;
|
|
StabTime = action.StabTime;
|
|
StartStop = 1;
|
|
}
|
|
bool CompareSetFlowArgs(Action action)
|
|
{
|
|
return (FlowMId == -1 || FlowMId == action.FlowMId) &&
|
|
(RegVId == -1 || RegVId == action.RegVId) &&
|
|
(StartStop == -1 || StartStop == 1);
|
|
}
|
|
|
|
///----------------------------------------------------------------------------------------------
|
|
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 = 1,
|
|
};
|
|
}
|
|
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 = 1;
|
|
}
|
|
bool CompareStartTestArgs(Action action)
|
|
{
|
|
return (FlowMId == -1 || FlowMId == action.FlowMId) &&
|
|
(DivId == -1 || DivId == action.DivId) &&
|
|
(StartStop == -1 || StartStop == 1);
|
|
}
|
|
|
|
///----------------------------------------------------------------------------------------------
|
|
public static Action Stop()
|
|
{
|
|
return new Action()
|
|
{
|
|
ActionId = ActionID.Stop,
|
|
StartStop = 0,
|
|
};
|
|
}
|
|
void SetStopArgs(Action action)
|
|
{
|
|
StartStop = 0;
|
|
}
|
|
bool CompareStopArgs(Action action)
|
|
{
|
|
return (StartStop == -1 || StartStop == 0);
|
|
}
|
|
|
|
///----------------------------------------------------------------------------------------------
|
|
public static Action SwitchDiverter(int divId, bool toTank)
|
|
{
|
|
return new Action
|
|
{
|
|
ActionId = ActionID.SwitchDiverter,
|
|
DivId = divId,
|
|
ToTank = toTank,
|
|
};
|
|
}
|
|
void SetSwitchDiverterArgs(Action action)
|
|
{
|
|
DivId = action.DivId;
|
|
ToTank = action.ToTank;
|
|
}
|
|
bool CompareSwitchDiverterArgs(Action action)
|
|
{
|
|
return (DivId == -1 || DivId == action.DivId);
|
|
}
|
|
|
|
///----------------------------------------------------------------------------------------------
|
|
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.Stop: SetStopArgs(action); return;
|
|
case ActionID.SwitchDiverter: SetSwitchDiverterArgs(action); return;
|
|
default: return;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether there is a conflict in usage of arguments.
|
|
/// </summary>
|
|
/// <param name="action">2nd action</param>
|
|
/// <returns>true if there is no conflict</returns>
|
|
bool CompareSharedArgs(Action action)
|
|
{
|
|
switch (action.ActionId)
|
|
{
|
|
case ActionID.ChangeRoute: return CompareChangeRouteArgs(action);
|
|
case ActionID.MeasureFlow: return CompareMeasureFlowArgs(action);
|
|
case ActionID.SetFlow: return CompareSetFlowArgs(action);
|
|
case ActionID.StartTest: return CompareStartTestArgs(action);
|
|
case ActionID.Stop: return CompareStopArgs(action);
|
|
case ActionID.SwitchDiverter: return CompareSwitchDiverterArgs(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.CompareSharedArgs(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.SetFlow:
|
|
args = string.Format("Etalon={0} RV={1} Par1={2} Par2={3}", FlowMId, RegVId, FlowRegP1, FlowRegP2);
|
|
break;
|
|
case ActionID.MeasureFlow:
|
|
args = string.Format("Etalon={0}", FlowMId);
|
|
break;
|
|
case ActionID.StartTest:
|
|
args = string.Format("Etalon={0} TotalP={1} MassP={2}", FlowMId, TotalPulsesCount, MassPulsesCount);
|
|
break;
|
|
default:
|
|
args = string.Empty;
|
|
break;
|
|
}
|
|
|
|
return string.Format(" {0} {1}", ActionId, args);
|
|
}
|
|
}
|
|
}
|