684 lines
30 KiB
C#
684 lines
30 KiB
C#
///
|
|
/// Copyright (c) 2013-2019 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Text;
|
|
using System.IO.Ports;
|
|
using System.Collections.Generic;
|
|
using Config.Entities;
|
|
using Dirichlet.Numerics;
|
|
using TBF.BenchControl.Generic;
|
|
using TBF.BenchControl.GenericDevices;
|
|
using log4net;
|
|
|
|
namespace TBF.BenchControl.Elde
|
|
{
|
|
public class ControlBoardDev : ComponentBase, IDevice, IValveControl
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(ControlBoardDev));
|
|
public override string ToString() { return string.Format("ControlBoard({0})", Cfg.ToString(1)); }
|
|
|
|
const int FiltersCount = 8;
|
|
|
|
readonly ControlBoardCfg controlBoardCfg;
|
|
|
|
///
|
|
/// Reference to the control board component
|
|
///
|
|
IControlCom controlCom;
|
|
|
|
/// <summary>
|
|
/// Emergency stop signal state updated by RunDevice().
|
|
/// 'modelessDlg' is notified about the changes and uses this information to change its visibility.
|
|
/// </summary>
|
|
//UiBridge.EmergencyStopEventArgs.State emergencyStopState;
|
|
|
|
|
|
///
|
|
/// Public read only wrappers for Elde software component fields
|
|
///
|
|
/// rvNr1 = 1 .. nrRegulValves (one based)
|
|
/// wmNr0 = 0 .. nrWaterMeters-1 (zero based)
|
|
/// tmpNr0 = 0 .. nrTempMeters-1 (zero based)
|
|
/// prsNr0 = 0 .. nrPressureMeters-1 (zero based)
|
|
///
|
|
public StatusP StatusP { get { return controlCom.StatusP; } }
|
|
public int EtPulses(int wmNr1) { return controlCom.EtPulses(wmNr1); }
|
|
public int EtPulsesK { get { return controlCom.EtPulsesK; } }
|
|
public int EtPulses2 { get { return controlCom.EtPulses2; } } /// DEWA_300: pulses from I12
|
|
public int EtPulses3 { get { return controlCom.EtPulses3; } } /// DEWA_300: pulses from I13
|
|
public UInt16 WMeterPulses(int wmNr1) { return controlCom.WMeterPulses(wmNr1); }
|
|
public int WMeterReference(int wmNr0) { return controlCom.WMeterReference(wmNr0); }
|
|
public uint RegulValveDAC(int rvNr0) { return controlCom.RegulValveDAC(rvNr0); }
|
|
public float Pressure(int prsNr0) { return controlCom.Pressure(prsNr0); }
|
|
public float Temperature(int tmpNr0) { return controlCom.Temperature(tmpNr0); }
|
|
public RegulValveState RegulValveState(int rvNr1) { return (RegulValveState)controlCom.RegulValveState(rvNr1); }
|
|
public UInt128 RRoute { get { return controlCom.RRoute; } }
|
|
public uint DivTime(int id) { return controlCom.DivTime(id); }
|
|
public float TTime { get { return controlCom.TTime; } }
|
|
public float ImpulseTime(int wmNr1) { return controlCom.ImpulseTime(wmNr1); }
|
|
public uint FmState { get { return controlCom.FmState; } }
|
|
public uint BeginState(int wmNr0) { return controlCom.BeginState(wmNr0); }
|
|
public double ReferenceFreq { get { return controlCom.ReferenceFreq; } } /// In [Hz] 0..2500, nom.=2000
|
|
public double ReferenceFreqs(int i) { return controlCom.ReferenceFreqs(i); }
|
|
public double ReferenceFlow { get { return controlCom.ReferenceFlow; } }
|
|
public float RValvePosition(int rvNr1) { return controlCom.RValvePosition(rvNr1); }
|
|
public float DivSamples(int time, int divIx0) { return controlCom.DivSamples(time, divIx0); } /// Time unit is 2 ms
|
|
public int ScopeSamples(int i, int j, int k) { return controlCom.ScopeSamples(i, j, k); }
|
|
public ulong DigitalInputs { get { return controlCom.DigitalInputs; } }
|
|
public float AnalogInput(int adcNr0) { return controlCom.AnalogInput(adcNr0); }
|
|
public uint AnalogInputRaw(int adcNr0, int bank) { return controlCom.AnalogInputRaw(adcNr0, bank); } /// adcNr0: 0=RV1, 1=RV2,... bank: 0=RV, 1=Temp
|
|
public float ReferenceVolume { get { return controlCom.TotalRefVolume; } }
|
|
public float VyslExt(int wmNr0, int what) { return controlCom.VyslExt(wmNr0, what); }
|
|
public uint[] CyclePar { get { return controlCom.CyclePar; } set { controlCom.CyclePar = value; } }
|
|
public uint[] WMeterCont { get { return controlCom.WMeterCont; } }
|
|
public bool ManualUIAllowed { get { return controlCom.ManualUIAllowed; } set { controlCom.ManualUIAllowed = value; } }
|
|
public float ValveOpenCloseTime { get { return controlCom.ValveOpenCloseTime; } }
|
|
|
|
/// <summary> Extracted from the StatusP in RunDeviceBefore </summary>
|
|
public bool EmergencyStop { get { return emergencyStop; } }
|
|
bool emergencyStop;
|
|
bool previousEmergencyStop;
|
|
|
|
|
|
public void DiverterToTank(int flowMtrNr)
|
|
{
|
|
cbCommandQueue.Enqueue(new SendCommandArgs(Command.Start, flowMtrNr, int.MaxValue, int.MaxValue, TestMethods.Diverter | TestMethods.Synchro, StopDevs.None));
|
|
}
|
|
///
|
|
public void DiverterToSink(int flowMtrNr)
|
|
{
|
|
cbCommandQueue.Enqueue(new SendCommandArgs(Command.Stop, 0, 0, 0, TestMethods.Diverter,
|
|
StopDevs.Diverter | StopDevs.GatePulse | StopDevs.Reference | StopDevs.RegValveRegulation));
|
|
}
|
|
///
|
|
public void ReadDiverterTransition(int flowMtrNr)
|
|
{
|
|
cbCommandQueue.Enqueue(new SendCommandArgs(Command.ReadDivTransition, flowMtrNr, 0, 0, TestMethods.Diverter, 0));
|
|
}
|
|
|
|
///
|
|
/// Initialization data updated by constructors of children components
|
|
/// and sent to 'controlCom2panel' by SendCalibData() method.
|
|
///
|
|
#if DEWA_300 || ROMA_200
|
|
public float[,] TempCalibData = new float[16, 5];
|
|
#else
|
|
public float[,] TempCalibData = new float[8, 5];
|
|
#endif
|
|
public uint[] DiverterEdge; /// Created and initialized in this.Initialize()
|
|
public byte MeretProtocol = 0;
|
|
|
|
// Array length is the reference flowmeters count plus one
|
|
#if DN100 || FUZHOU_150 || FUZHOU_300 || IZRAEL_200 || SLM_150 || SENTEC || CEVAK_200
|
|
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
|
|
public byte[] MeretRS485Address = new byte[4];
|
|
public float[] EtCalib = new float[6] { 1, 1, 1, 1, 1, 1 };
|
|
#elif PUCHONG_200 || GENESIS || BERLIN || PETERSBURG_200 || RUM_MOB
|
|
public uint[,] RegValveCalib = new uint[16, 2] { {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500},
|
|
{100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500} };
|
|
public byte[] MeretRS485Address = new byte[4];
|
|
public float[] EtCalib = new float[7] { 1, 1, 1, 1, 1, 1, 1 };
|
|
#elif DEWA_300
|
|
public uint[,] RegValveCalib = new uint[16, 2] { {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500},
|
|
{100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500} };
|
|
public byte[] MeretRS485Address = new byte[4];
|
|
public float[] EtCalib = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 };
|
|
#elif ROMA_200
|
|
public uint[,] RegValveCalib = new uint[16, 2] { {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500},
|
|
{100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500}, {100,500} };
|
|
public byte[] MeretRS485Address = new byte[5];
|
|
public float[] EtCalib = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 };
|
|
#elif MUNICH || TORINO_50 || BADGER_MALA_TRAT || BADGER_STREDNA_TRAT || TORUN_50 || CEVAK_40 || TURA_IPERL || TURA_IPERL_NEW || TURA_SPECIAL || MURES_40 || FUZHOU_50 || SLM_50 || PETERSBURG_50 || KEMPNO_50 || BAHRAIN_50 || KRAKOW_50 || JUZNA_AFRIKA_50 || IZRAEL_25 || ZAMBIA || ZODINO || FEWA_50 || FILIPINY_50 || FUZHOU_100 || ALZIR_25
|
|
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
|
|
public byte[] MeretRS485Address = new byte[4];
|
|
public float[] EtCalib = new float[5] { 1, 1, 1, 1, 1 };
|
|
#elif IZRAEL_50 || SLM_END
|
|
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
|
|
public byte[] MeretRS485Address = new byte[7]; /// Modbus addresses of Pr1, Pr2, Pr3, Pr4, Pr5, Pr6, T9 (Izrael) or Pr1, Pr2, Pr3, Pr4, T9, T10 (SLM END)
|
|
public float[] EtCalib = new float[5] { 1, 1, 1, 1, 1 };
|
|
#elif WARSAW_END
|
|
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
|
|
public byte[] MeretRS485Address = new byte[4];
|
|
public float[] EtCalib = new float[5] { 1, 1, 1, 1, 1 };
|
|
#elif MALTA_WSD25
|
|
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
|
|
public byte[] MeretRS485Address = new byte[12];
|
|
public float[] EtCalib = new float[9] { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
|
#elif BADGER_VELKA_TRAT
|
|
public uint[,] RegValveCalib = new uint[8,2] {{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500},{100,500}};
|
|
public byte[] MeretRS485Address = new byte[4];
|
|
public float[] EtCalib = new float[8] { 1, 1, 1, 1, 1, 1, 1, 1 };
|
|
#endif
|
|
|
|
public uint[] BalanceRange = new uint[2];
|
|
|
|
|
|
|
|
Queue<SendCommandArgs> cbCommandQueue;
|
|
|
|
/// <summary>
|
|
/// Route: 128-bit word representing the current state of all valves and pumps
|
|
/// </summary>
|
|
public UInt128 Route { get { return benchModelRoute; } }
|
|
UInt128 benchModelRoute;
|
|
UInt128 valvesToInvert; /// Route = valesToInvert ^ RequiredRouteWithoutInvertedVlaves
|
|
readonly UInt128 routeMask; /// This mask masks out virtual valves, routeMask is set in the constructor
|
|
|
|
int[] filters;
|
|
float[] FMFreq;
|
|
int regConst;
|
|
int shortImp;
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Set values to be applied during a test
|
|
/// </summary>
|
|
/// <param name="filters">Filters for meter pulses</param>
|
|
/// <param name="pid">PID coefficient for flow control</param>
|
|
/// <param name="shortPulses">Short pulses mode (0 = off)</param>
|
|
public void SetFiltersPidShortPulses(int[] filters, float pid, int shortPulses)
|
|
{
|
|
this.filters = filters;
|
|
this.regConst = (int)pid;
|
|
this.shortImp = shortPulses;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the power of the selected pump
|
|
/// </summary>
|
|
/// <param name="index">Pump index 0 .. 5, invalid pump index sets all pumps to 0%</param>
|
|
/// <param name="power">Power (0.0f .. 100.0f)</param>
|
|
public void SetFMFreq(int index, float power)
|
|
{
|
|
bool pumpPowerChanged = false;
|
|
|
|
#if DN100 || MUNICH || FUZHOU_150
|
|
if ((FMFreq == null) || (FMFreq.Length != 2))
|
|
{
|
|
FMFreq = new float[2];
|
|
pumpPowerChanged = true; /// Forces sending a command using Command.None
|
|
}
|
|
#elif SLM_END || WARSAW_END
|
|
if ((FMFreq == null) || (FMFreq.Length != 4))
|
|
{
|
|
FMFreq = new float[4];
|
|
pumpPowerChanged = true; /// Forces sending a command using Command.None
|
|
}
|
|
#else /// all newer benches
|
|
if ((FMFreq == null) || (FMFreq.Length != 6))
|
|
{
|
|
FMFreq = new float[6];
|
|
pumpPowerChanged = true; /// Forces sending a command using Command.None
|
|
}
|
|
#endif
|
|
|
|
if (index >= 0 && index < FMFreq.Length && FMFreq[index] != power)
|
|
{
|
|
FMFreq[index] = power;
|
|
|
|
pumpPowerChanged = true; /// Forces sending a command using Command.None
|
|
|
|
log.DebugFormat("FMFreq=[{0}{1}{2}{3}{4}{5}]",
|
|
FMFreq[0].ToString(),
|
|
(FMFreq.Length > 1) ? ("," + FMFreq[1].ToString()) : "",
|
|
(FMFreq.Length > 2) ? ("," + FMFreq[2].ToString()) : "",
|
|
(FMFreq.Length > 3) ? ("," + FMFreq[3].ToString()) : "",
|
|
(FMFreq.Length > 4) ? ("," + FMFreq[4].ToString()) : "",
|
|
(FMFreq.Length > 5) ? ("," + FMFreq[5].ToString()) : "");
|
|
}
|
|
}
|
|
|
|
|
|
public void UpdateWeights()
|
|
{
|
|
/// Mettler-Toledo scales
|
|
for (int i = 0; i < MettlerToledo.Standard.BalanceDev.BalancesCount; i++)
|
|
{
|
|
controlCom.SetWeight(i, MettlerToledo.Standard.BalanceDev.Masses[i]);
|
|
}
|
|
|
|
/// Mettler-Toledo-multi scales (Badger Brno, ...)
|
|
for (int i = 0; i < MettlerToledo.Multi.BalanceDev.BalancesCount; i++)
|
|
{
|
|
controlCom.SetWeight(i, MettlerToledo.Multi.BalanceDev.Masses[i]);
|
|
}
|
|
|
|
/// Tanks (CEVAK, ...)
|
|
int firstTankIx = Math.Max(MettlerToledo.Standard.BalanceDev.BalancesCount, MettlerToledo.Multi.BalanceDev.BalancesCount);
|
|
|
|
for (int i = 0; i < Various.TankWithLevelMsrmnt.Tank.TanksCount; i++)
|
|
{
|
|
controlCom.SetWeight(firstTankIx + i, Various.TankWithLevelMsrmnt.Tank.Tanks[i].Volume);
|
|
}
|
|
}
|
|
|
|
|
|
public void SetReservoirTemp(int nr, float temp)
|
|
{
|
|
controlCom.SetReservoirTemp(nr, temp);
|
|
}
|
|
|
|
public ControlBoardDev()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
public ControlBoardDev(Generic.IComponentCfg cfg)
|
|
: base(cfg)
|
|
{
|
|
controlBoardCfg = cfg as ControlBoardCfg;
|
|
|
|
cbCommandQueue = new Queue<SendCommandArgs>();
|
|
lastSentFilters = new uint[FiltersCount];
|
|
|
|
#if DN100 || MUNICH || FUZHOU_150
|
|
FMFreq = new float[2] { 0, 0 }; /// Nr. of pumps: Fuzhou150=2, Fuzhou300=6, newer=6
|
|
#elif SLM_END || WARSAW_END
|
|
FMFreq = new float[4] { 0, 0, 0, 0 };
|
|
#else /// all newer benches
|
|
FMFreq = new float[6] { 0, 0, 0, 0, 0, 0 };
|
|
#endif
|
|
emergencyStop = false;
|
|
previousEmergencyStop = false;
|
|
|
|
routeMask = 0;
|
|
for (int i = 0; i < 128; i++)
|
|
{
|
|
if (i < controlBoardCfg.VirtualValvesRangeLo || i > controlBoardCfg.VirtualValvesRangeHi)
|
|
{
|
|
routeMask = routeMask | ((UInt128)1 << i);
|
|
}
|
|
}
|
|
|
|
log.Debug(this.ToString());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specific pre-initialization for control board only
|
|
/// </summary>
|
|
/// <param name="ctrlBrdComponent"></param>
|
|
public void InitializeComponent(
|
|
#if DN100
|
|
ControlCom2VB.ControlCom2panel ctrlBrdComponent,
|
|
#elif MUNICH || FUZHOU_150
|
|
ControlComponent3Munich.UserControl1 ctrlBrdComponent,
|
|
#elif FUZHOU_300
|
|
ControlComponent3F300.UserControl1 ctrlBrdComponent,
|
|
#elif IZRAEL_200 || PUCHONG_200 || GENESIS || BERLIN || SLM_150 || PETERSBURG_200
|
|
ControlComponent_Izrael2014.UserControl1 ctrlBrdComponent,
|
|
#else /// all newer benches
|
|
ControlComponent_Torino2015.UserControl1 ctrlBrdComponent,
|
|
#endif
|
|
UInt128 valvesToInvert,
|
|
double[] tankCapacities)
|
|
{
|
|
this.valvesToInvert = valvesToInvert;
|
|
this.benchModelRoute = valvesToInvert;
|
|
|
|
if (controlBoardCfg.DebugLevel == DebugMode.Simulate)
|
|
{
|
|
controlCom = new ControlComSim();
|
|
}
|
|
else
|
|
{
|
|
/// Default number of scales (and BalanceRange length) is 2.
|
|
/// If there are more scales, BalanceRange length is larger.
|
|
int scalesCnt = Math.Max(2, tankCapacities.Length);
|
|
BalanceRange = new uint[scalesCnt];
|
|
for (int i = 0; i < scalesCnt; i++)
|
|
{
|
|
BalanceRange[i] = (uint)((i < tankCapacities.Length) ? tankCapacities[i] : 0);
|
|
}
|
|
controlCom = new ControlComWrap(ctrlBrdComponent);
|
|
}
|
|
}
|
|
|
|
/// <summary>Initialize this device</summary>
|
|
public void Initialize()
|
|
{
|
|
int divertersCount = BenchControl.Elde.Diverter.Diverter.DivertersCount;
|
|
|
|
DiverterEdge = new uint[divertersCount];
|
|
for (int i = 0; i < divertersCount; i++)
|
|
{
|
|
DiverterEdge[i] = (uint)BenchControl.Elde.Diverter.Diverter.Diverters[i].ThresholdGate;
|
|
controlCom.SetDivLimit(i, (uint)BenchControl.Elde.Diverter.Diverter.Diverters[i].ThresholdLo,
|
|
(uint)BenchControl.Elde.Diverter.Diverter.Diverters[i].ThresholdHi);
|
|
}
|
|
|
|
controlCom.SendCalibData(RegValveCalib,
|
|
MeretRS485Address,
|
|
controlBoardCfg.ComPortNr,
|
|
TempCalibData,
|
|
EtCalib,
|
|
DiverterEdge,
|
|
BalanceRange,
|
|
MeretProtocol);
|
|
|
|
log.FatalFormat("Successfully initialized device {0}", ToString());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Run this device
|
|
/// </summary>
|
|
public void RunDeviceBefore()
|
|
{
|
|
if (DebugLevel == DebugMode.Simulate) return;
|
|
|
|
controlCom.RunDeviceBefore();
|
|
|
|
previousEmergencyStop = emergencyStop;
|
|
emergencyStop = (controlCom.StatusP & StatusP.EmgcyStopActive) != 0;
|
|
|
|
if (emergencyStop && !previousEmergencyStop)
|
|
{
|
|
Program.MainWnd.Invoke(new ShowEmergencyStopFormDlgt(ShowEmergencyStopForm));
|
|
|
|
/// Stop the cycle - Press 'STOP' button in the BenchControlPanel
|
|
TBF.UiBridge.Bridge.Ui2Bench(TBF.UiBridge.UI2BenchCmd.Stop);
|
|
}
|
|
else if (!emergencyStop && previousEmergencyStop)
|
|
{
|
|
UiBridge.Bridge.OnEmergencyStopChanged(this,UiBridge.EmergencyStopEventArgs.State.CloseForm);
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Used in RunDeviceAfter() when sending commands
|
|
///
|
|
UInt128 lastSentRoute;
|
|
uint[] lastSentFilters;
|
|
float[] lastSentFMFreq;
|
|
int lastsentRegConst;
|
|
int lastSentShortImp;
|
|
|
|
/// <summary>
|
|
/// Run this device
|
|
/// </summary>
|
|
public void RunDeviceAfter()
|
|
{
|
|
if (DebugLevel == DebugMode.Simulate) return;
|
|
|
|
UpdateWeights();
|
|
|
|
/// Modify queue in case of emergency stop
|
|
if (emergencyStop && !previousEmergencyStop)
|
|
{
|
|
/// SendCommand() arguments to clear the emergency stop state
|
|
cbCommandQueue.Clear();
|
|
cbCommandQueue.Enqueue(new SendCommandArgs(Command.Stop, 0, 0, 0, 0, StopDevs.All));
|
|
}
|
|
|
|
/// Prepare uintFilters array and evaluate changes
|
|
uint[] uintFilters = new uint[FiltersCount];
|
|
uintFilters[0] = (filters != null && filters.Length > 0) ? (uint)filters[0] : 0;
|
|
bool filtersAreDifferent = (uintFilters[0] != lastSentFilters[0]);
|
|
for (int i = 1; i < FiltersCount; i++)
|
|
{
|
|
uintFilters[i] = (filters != null && filters.Length > i) ? (uint)filters[i] : uintFilters[i - 1];
|
|
filtersAreDifferent |= (uintFilters[i] != lastSentFilters[i]);
|
|
}
|
|
|
|
/// Evaluate FMFreq changes
|
|
bool fmFreqsAreDifferent = false;
|
|
if ((FMFreq == null) || (lastSentFMFreq == null) || (FMFreq.Length != lastSentFMFreq.Length))
|
|
{
|
|
fmFreqsAreDifferent = true;
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < FMFreq.Length; i++)
|
|
{
|
|
if (FMFreq[i] != lastSentFMFreq[i])
|
|
{
|
|
fmFreqsAreDifferent = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cbCommandQueue.Count > 0)
|
|
{
|
|
/// There is a command in the queue
|
|
///
|
|
controlCom.SendCommand(cbCommandQueue.Dequeue(), (benchModelRoute & routeMask), uintFilters, FMFreq, regConst, shortImp);
|
|
|
|
lastSentRoute = (benchModelRoute & routeMask);
|
|
lastSentFilters = uintFilters;
|
|
lastSentFMFreq = FMFreq;
|
|
lastsentRegConst = regConst;
|
|
lastSentShortImp = shortImp;
|
|
}
|
|
else if (((benchModelRoute & routeMask) != lastSentRoute) ||
|
|
filtersAreDifferent ||
|
|
fmFreqsAreDifferent ||
|
|
(lastsentRegConst != regConst) ||
|
|
(lastSentShortImp != shortImp))
|
|
{
|
|
/// Command queue is mepty, but 'route', pump frequency, PID coef., filters or shortImp have changed
|
|
///
|
|
controlCom.SendCommand(new SendCommandArgs(Command.None, 0, 0, 0, 0, 0), (benchModelRoute & routeMask), uintFilters, FMFreq, regConst, shortImp);
|
|
|
|
lastSentRoute = (benchModelRoute & routeMask);
|
|
lastSentFilters = uintFilters;
|
|
lastSentFMFreq = FMFreq;
|
|
lastsentRegConst = regConst;
|
|
lastSentShortImp = shortImp;
|
|
}
|
|
|
|
controlCom.RunDeviceAfter();
|
|
}
|
|
|
|
/// <summary>Stop this device</summary>
|
|
public void StopDevice() { }
|
|
public void StopDevice2() { }
|
|
|
|
|
|
delegate void ShowEmergencyStopFormDlgt();
|
|
///
|
|
void ShowEmergencyStopForm()
|
|
{
|
|
(new TBF.UI.Shared.EmergencyStopForm()).Show();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Sends a command to the control board.
|
|
/// </summary>
|
|
/// <param name="cmd">See ControlBoard.Command enum</param>
|
|
/// <param name="refFlowmtrNr">Number of the etalon/reference (1..5)</param>
|
|
/// <param name="route">State of valves, 128-bit word</param>
|
|
/// <param name="totalRefPulses">kolko impulzov ma trvat skuska</param>
|
|
/// <param name="testMethods">See ControlBoard.TestMethods enum</param>
|
|
/// <param name="filterConstant">0 = No filtering (0..255)</param>
|
|
/// <param name="regConst">Coefficient used to control reg. valves (1..100)</param>
|
|
/// <param name="shortImp">0 = default value, 1 = spec. processing of very short pulses</param>
|
|
/// <param name="stopDevs">What to stop</param>
|
|
public void SendCommand(Command cmd, int refFlowmtrNr, int totalRefPulses, int massRefPulses,
|
|
TestMethods testMethods, StopDevs stopDevs)
|
|
{
|
|
cbCommandQueue.Enqueue(new SendCommandArgs(cmd, refFlowmtrNr, totalRefPulses, massRefPulses, testMethods, stopDevs));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set valves to new positions.
|
|
/// </summary>
|
|
/// <param name="valvesToOpen">'ulong' with bits of valves to open set to '1'</param>
|
|
/// <param name="valvesToClose">'ulong' with bits of valves to close set to '1'</param>
|
|
/// <returns>'ulong' with bits of valves that have changed set to '1'</returns>
|
|
public UInt128 SetValves(UInt128 valvesToOpen, UInt128 valvesToClose, IList<Elde.ValveEx.Valve> extendedValves)
|
|
{
|
|
UInt128 oldRoute = benchModelRoute;
|
|
benchModelRoute = (((benchModelRoute ^ valvesToInvert) | valvesToOpen) & (~valvesToClose)) ^ valvesToInvert;
|
|
foreach (var extV in extendedValves) extV.UpdateRoute(ref benchModelRoute);
|
|
log.DebugFormat("SetValves(x,x), new route = {0}", Utils.RouteToStr(benchModelRoute));
|
|
return oldRoute ^ benchModelRoute;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set Route to value returned by RRoute. Take virtual valves into account.
|
|
/// </summary>
|
|
/// <returns>'ulong' with bits of valves that have changed set to '1'</returns>
|
|
public UInt128 SyncRoute()
|
|
{
|
|
UInt128 oldRoute = benchModelRoute;
|
|
benchModelRoute = (RRoute & routeMask) | (benchModelRoute & (~routeMask));
|
|
log.DebugFormat("SyncRoute(), new route = {0}", Utils.RouteToStr(benchModelRoute));
|
|
return oldRoute ^ benchModelRoute;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Regulation valves control.
|
|
/// </summary>
|
|
/// <param name="valveNo">Regulation valve nr. (1..5)</param>
|
|
/// <param name="valveMode">Valve regulation mode, see the enum</param>
|
|
/// <param name="valveValue">Target position or target frequency or pulse duration</param>
|
|
/// <param name="stableTime">Stabilization time when setting the flow: 0=200ms, step 50ms, max. 1.5 sec.</param>
|
|
public void ValveMove(int valveNo, RegulValveMode valveMode, float[] valveValue, int stableTime)
|
|
{
|
|
controlCom.ValveMove(valveNo, valveMode, valveValue, stableTime);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Open one valve and/or close one valve.
|
|
/// Events: ValvesSet
|
|
/// </summary>
|
|
/// <param name="valveOpen">Valve to be opened</param>
|
|
/// <param name="valveClose">Valve to be closed</param>
|
|
/// <returns>Created operation</returns>
|
|
public IOperation SetValvesOp(IValve valveOpen, IValve valveClose)
|
|
{
|
|
return new SetValvesOp(this, valveOpen, valveClose);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Open and/or close multiple valves.
|
|
/// Events: ValvesSet
|
|
/// </summary>
|
|
/// <param name="valvesOpen">A list of valves to be opened</param>
|
|
/// <param name="valvesClose">A list of valves to be closed</param>
|
|
/// <returns>Created operation</returns>
|
|
public IOperation SetValvesOp(IList<IValve> valvesOpen, IList<IValve> valvesClose)
|
|
{
|
|
return new SetValvesOp(this, valvesOpen, valvesClose);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts the measurement.
|
|
/// Events: MeasurementStarted
|
|
/// </summary>
|
|
/// <param name="flowMeter">Flow meter</param>
|
|
/// <param name="readers">An array of register readers</param>
|
|
/// <param name="refPulses">Number of reference pulses to complete the test</param>
|
|
/// <returns>Created operation</returns>
|
|
public IOperation StartMeasurementOp(OutputPath outputPath, TestMethods method,
|
|
double requiredFlowLo, double requiredFlowHi, int refPulses)
|
|
{
|
|
if (controlBoardCfg.DebugLevel == DebugMode.Simulate)
|
|
{
|
|
return new Operations.ReturnGivenEventOp(Event.MeasurementStarted);
|
|
}
|
|
else
|
|
{
|
|
return new StartMeasurementOp(this, outputPath, method, requiredFlowLo, requiredFlowHi, refPulses);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts the measurement.
|
|
/// Events: MeasurementStarted
|
|
/// </summary>
|
|
/// <param name="flowMeter">Flow meter</param>
|
|
/// <param name="readers">An array of register readers</param>
|
|
/// <param name="refPulses">Number of reference pulses to complete the test</param>
|
|
/// <returns>Created operation</returns>
|
|
public IOperation StartProlongedMeasurementOp(OutputPath outputPath, TestMethods method,
|
|
double requiredFlowLo, double requiredFlowHi,
|
|
int totalRefPulses, int massRefPulses)
|
|
{
|
|
if (controlBoardCfg.DebugLevel == DebugMode.Simulate)
|
|
{
|
|
return new Operations.ReturnGivenEventOp(Event.MeasurementStarted);
|
|
}
|
|
else
|
|
{
|
|
return new StartMeasurementOp(this, outputPath, method, requiredFlowLo, requiredFlowHi, totalRefPulses, massRefPulses);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read diverter samples from the control board and calculated the transition time.
|
|
/// Events: Event.None
|
|
/// </summary>
|
|
/// <param name="div">Diverter</param>
|
|
/// <param name="runsCountWhenSendingCmd">State machine ticks from test start/end when diverter read command is issued (obsolete)</param>
|
|
/// <param name="runsCountWhenReadingDiv">State machine ticks from test start/end when diverter samples are read</param>
|
|
/// <param name="transitionTimeSec">FloatBox for the resulting transition time in s</param>
|
|
/// <param name="plotter">Statistics for plotting diverter transitions</param>
|
|
/// <param name="batchNr">Batch number</param>
|
|
/// <param name="testName">Test name (without repetitions)</param>
|
|
/// <param name="repetition">Repetition number</param>
|
|
/// <returns>Created operation</returns>
|
|
public IOperation ReadDiverterTransitionOp(IDiverter div, int runsCountWhenSendingCmd, int runsCountWhenReadingDiv, bool toTank,
|
|
Sequences.Statistics plotter, int batchNr, string testName, int repetition)
|
|
{
|
|
if (controlBoardCfg.DebugLevel == DebugMode.Simulate)
|
|
{
|
|
return new Operations.ReturnGivenEventOp(Event.None);
|
|
}
|
|
else
|
|
{
|
|
return new ReadDiverterTransitionOp(this, div, runsCountWhenSendingCmd, runsCountWhenReadingDiv, toTank, plotter, batchNr, testName, repetition);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Queries th econtrol board whether the measurement was completed.
|
|
/// Events: MeasurementCompleted or None
|
|
/// </summary>
|
|
/// <returns>Created operation</returns>
|
|
public IOperation QueryMeasurementEndOp()
|
|
{
|
|
return new QueryMeasurementEndOp(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stop controls board flow regulation operation
|
|
/// Events: FlowRegulationStopped
|
|
/// </summary>
|
|
/// <returns>Created operation</returns>
|
|
public IOperation StopFlowRegulationOp(OutputPath outputPath)
|
|
{
|
|
return new StopFlowRegulationOp(this, outputPath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stop the previous control board operation (diverter, gate, etc.)
|
|
/// Events: PreviousStopped
|
|
/// </summary>
|
|
/// <returns>Created operation</returns>
|
|
public IOperation StopPreviousOp()
|
|
{
|
|
return new StopPreviousOp(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends commands to the control board.
|
|
/// Events: Event.None, Event.CommandCompleted
|
|
/// </summary>
|
|
/// <param name="commandOnStartOp">Command sent to CB when this operation starts</param>
|
|
/// <param name="commandOnStopOp">Command sent to CB when this operation stops</param>
|
|
/// <param name="testMethod">Test method parameter</param>
|
|
/// <returns>Created operation</returns>
|
|
public IOperation ExecuteCommandOp(Command commandOnStartOp, Command commandOnStopOp, TestMethods testMethod)
|
|
{
|
|
return new ExecuteCommandOp(this, commandOnStartOp, commandOnStopOp, testMethod);
|
|
}
|
|
}
|
|
}
|