382 lines
20 KiB
C#
382 lines
20 KiB
C#
///
|
|
/// Copyright (c) 2013-2015 Sensus Metering Systems
|
|
///
|
|
using System;
|
|
using log4net;
|
|
|
|
namespace TBF.BenchControl.Elde
|
|
{
|
|
public class ControlComWrap : IControlCom
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(ControlComWrap));
|
|
/// Fatal: SendCalibData(), DoSendCalibData()
|
|
/// Info: SendCommand(), ValveMove(), StatusP
|
|
/// Debug: Weight[ix]
|
|
|
|
///
|
|
/// Properties
|
|
///
|
|
public StatusP StatusP { get { return (StatusP)ctrlBrdComponent.StatusP; } }
|
|
#if DN100 || MUNICH || FUZHOU150
|
|
public float ReferenceFreq { get { return 1000.0f * ctrlBrdComponent.referenceFreq; } } /// In [Hz] 0..2500, nom.=2000
|
|
#else /// all newer benches
|
|
/// <summary>
|
|
/// In case of I11, I12
|
|
/// referenceFreq[0] = I11 + I12
|
|
/// referenceFreq[1] = I11
|
|
/// referenceFreq[2] = I12
|
|
/// otherwise
|
|
/// referenceFreq[0] = I2 or I3 or I4
|
|
/// </summary>
|
|
public float ReferenceFreq { get { return 1000.0f * ctrlBrdComponent.referenceFreq[0]; } } /// In [Hz] 0..2500, nom.=2000
|
|
#endif
|
|
public int EtPulses(int wmNr0) { return (int)ctrlBrdComponent.etPulses[wmNr0]; }
|
|
public UInt16 WMeterPulses(int wmNr0) { return (UInt16)ctrlBrdComponent.wMeterPuls[wmNr0]; }
|
|
public int WMeterReference(int wmNr0) { return (int)ctrlBrdComponent.wMeterReference[wmNr0]; }
|
|
public uint RegulValveDAC { get { return ctrlBrdComponent.StavDA; } }
|
|
public float Pressure(int prsNr0) { return ctrlBrdComponent.pressure[prsNr0]; }
|
|
public float Temperature(int tmpNr0) { return ctrlBrdComponent.temperature[tmpNr0]; }
|
|
public RegulValveState RegulValveState(int rvNr1) { return (RegulValveState)ctrlBrdComponent.rValveStatus[rvNr1 - 1]; }
|
|
public ulong RRoute { get { return ctrlBrdComponent.rRoute; } }
|
|
public uint DivTime { get { return ctrlBrdComponent.divTime; } }
|
|
public float TTime { get { return ctrlBrdComponent.Ttime; } }
|
|
#if DN100 || MUNICH || FUZHOU150
|
|
public uint FmState { get { return ctrlBrdComponent.fMState; } }
|
|
#else //if everything newer
|
|
public uint FmState { get { return ctrlBrdComponent.fMState[0]; } } /// TODO: index
|
|
#endif
|
|
public uint BeginState(int wmNr0) { return ctrlBrdComponent.beginSt[wmNr0]; }
|
|
public float ReferenceFlow { get { return ctrlBrdComponent.referenceFlow; } }
|
|
public float RValvePosition(int rvNr1)
|
|
{
|
|
//return ctrlBrdComponent.RValvePosition[rvNr1 - 1];
|
|
return ctrlBrdComponent.Analogy[rvNr1 - 1]; /// Fixes bug: RValvePosition returns 0 all the time
|
|
}
|
|
public float DivSamples(int ms) { return ctrlBrdComponent.DIVSamples[ms, 0]; }
|
|
public int ScopeSamples(int i, int j, int k) { return ctrlBrdComponent.ScopeSamples[i, j, k]; }
|
|
public ulong DigitalInputs { get { return (ulong)ctrlBrdComponent.Vstupy; } }
|
|
public float AnalogInput(int adcNr0) { return ctrlBrdComponent.Analogy[adcNr0]; }
|
|
public uint AnalogInputRaw(int adcNr0, int bank) { return ctrlBrdComponent.AnalogyRaw[adcNr0, bank]; } /// bank0=RV, bank1=Temp
|
|
|
|
#if DN100 || MUNICH || BADGER_MALA_TRAT || BADGER_VELKA_TRAT || FUZHOU40 || FUZHOU150 || FUZHOU300 || PT200IL || PUCHONG_PT200 || TORINO50 || TORUN_PT50_2015 || CEVAK_PT40_272 || MURES_PT40 || GENESIS
|
|
public float TotalRefVolume { get { return ctrlBrdComponent.ReferenceVolume; } }
|
|
public float MassRefVolume { get { return ctrlBrdComponent.ReferenceVolume; } }
|
|
#else
|
|
public float TotalRefVolume { get { return ctrlBrdComponent.ReferenceVolume[0]; } }
|
|
public float MassRefVolume { get { return ctrlBrdComponent.ReferenceVolume[1]; } }
|
|
#endif
|
|
|
|
#if SLM_END || WARSAW_END
|
|
public uint GetCyclePar(int ix) { return ctrlBrdComponent.CyclePar[ix]; }
|
|
public void SetCyclePar(int ix, uint val) { ctrlBrdComponent.CyclePar[ix] = val; }
|
|
#else
|
|
public uint GetCyclePar(int ix) { return 0; } /// Dummy
|
|
public void SetCyclePar(int ix, uint val) { return; } /// Dummy
|
|
#endif
|
|
|
|
public float VyslExt(int wmNr0, int what) { return ctrlBrdComponent.VyslExt[wmNr0, what]; }
|
|
public void SetWeight(int pos, double mass)
|
|
{
|
|
ctrlBrdComponent.Weight[pos] = (float)mass;
|
|
log.DebugFormat("SetWeight(pos={0}, mass={1}", pos, mass);
|
|
}
|
|
|
|
|
|
///
|
|
/// Reference to the control board component
|
|
///
|
|
#if DN100
|
|
private ControlCom2VB.ControlCom2panel ctrlBrdComponent;
|
|
#elif MUNICH
|
|
private ControlComponent3Munich.UserControl1 ctrlBrdComponent;
|
|
#elif FUZHOU150
|
|
private ControlComponent3Munich.UserControl1 ctrlBrdComponent;
|
|
#elif FUZHOU300
|
|
private ControlComponent3F300.UserControl1 ctrlBrdComponent;
|
|
#elif PT200IL || PUCHONG_PT200 || GENESIS
|
|
private ControlComponent_Izrael2014.UserControl1 ctrlBrdComponent;
|
|
#else /// newer benches
|
|
private ControlComponent_Torino2015.UserControl1 ctrlBrdComponent;
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Constructor that initializes the control board component reference
|
|
/// </summary>
|
|
/// <param name="ctrlBrdComponent"></param>
|
|
#if DN100
|
|
public ControlComWrap(ControlCom2VB.ControlCom2panel ctrlBrdComponent)
|
|
#elif MUNICH
|
|
public ControlComWrap(ControlComponent3Munich.UserControl1 ctrlBrdComponent)
|
|
#elif FUZHOU150
|
|
public ControlComWrap(ControlComponent3Munich.UserControl1 ctrlBrdComponent)
|
|
#elif FUZHOU300
|
|
public ControlComWrap(ControlComponent3F300.UserControl1 ctrlBrdComponent)
|
|
#elif PT200IL || PUCHONG_PT200 || GENESIS
|
|
public ControlComWrap(ControlComponent_Izrael2014.UserControl1 ctrlBrdComponent)
|
|
#else /// all newer benches
|
|
public ControlComWrap(ControlComponent_Torino2015.UserControl1 ctrlBrdComponent)
|
|
#endif
|
|
{
|
|
this.ctrlBrdComponent = ctrlBrdComponent;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Sends calibration and configuration data to the control board.
|
|
/// </summary>
|
|
/// <param name="rvCalib">Regulating valves calib.coefs, ix1 = valve nr. (1..5), ix2 = coef.nr. (0..1), values typ. c0 = 0, c1 = 0.2</param>
|
|
/// <param name="meretA">Meret address, index = 0..1, value typ. 99 and 100</param>
|
|
/// <param name="usedCom">COM port number of the control board (typ. 1)</param>
|
|
/// <param name="tempCalib">Temp.calc.coefs, ix1 = temp.sens.nr. (0..7 ???), ix2 = coef.nr</param>
|
|
/// <param name="etCalib">Etalon nominal values</param>
|
|
/// <param name="divEdge">Percentages for switching of diverters, ix = diverter nr.(0,1), typ.value 50 (%)</param>
|
|
/// <param name="balanceRange">Balance range = volume of the tanks on the balaces (ix=0,1)</param>
|
|
public void SendCalibData(uint[,] rvCalib, byte[] meretA, int usedCom, float[,] tempCalib,
|
|
float[] etCalib, uint[] divEdge, uint[] balanceRange)
|
|
{
|
|
if (Program.MainWnd.InvokeRequired)
|
|
{
|
|
/// When SendCalibData(...) called from the worker thread
|
|
object[] args = new object[] { rvCalib, meretA, usedCom, tempCalib, etCalib, divEdge, balanceRange };
|
|
Program.MainWnd.Invoke((SendCalibDataDlgt)DoSendCalibData, args); /// Invoke required as component was created in UI thread
|
|
}
|
|
else
|
|
{
|
|
/// When SendCalibData(...) called from the UI thread
|
|
DoSendCalibData(rvCalib, meretA, usedCom, tempCalib, etCalib, divEdge, balanceRange);
|
|
}
|
|
}
|
|
///
|
|
delegate void SendCalibDataDlgt(uint[,] rvCalib, byte[] meretA, int usedCom, float[,] tempCalib,
|
|
float[] etCalib, uint[] divEdge, uint[] balanceRange);
|
|
///
|
|
private void DoSendCalibData(uint[,] rvCalib, byte[] meretA, int usedCom, float[,] tempCalib,
|
|
float[] etCalib, uint[] divEdge, uint[] balanceRange)
|
|
{
|
|
//TBF.UiBridge.Bridge.OnLog(this, string.Format("{0} SendCalibData(COM{1}) rvCalib[0,0]={2} rvCalib[0,1]={3} rvCalib[1,0]={4} rvCalib[1,1]={5}\r\n",
|
|
// DateTime.Now.ToLongTimeString(), usedCom,
|
|
// rvCalib[0,0], rvCalib[0,1], rvCalib[1,0], rvCalib[1,1]));
|
|
log.Fatal("SendCalibData(...)");
|
|
for (int i = 0; i < rvCalib.GetLength(0); i++)
|
|
for (int j = 0; j < rvCalib.GetLength(1); j++)
|
|
log.FatalFormat(" rvCalib[{0},{1}] = {2}", i, j, rvCalib[i,j]);
|
|
for (int i = 0; i < meretA.Length; i++) log.FatalFormat(" meretA[{0}] = {1}", i, meretA[i]);
|
|
log.FatalFormat(" usedCom = {0}", usedCom);
|
|
for (int i = 0; i < tempCalib.GetLength(0); i++)
|
|
for (int j = 0; j < tempCalib.GetLength(1); j++)
|
|
log.FatalFormat(" tempCalib[{0},{1}] = {2}", i, j, tempCalib[i, j]);
|
|
for (int i = 0; i < etCalib.Length; i++) log.FatalFormat(" etCalib[{0}] = {1}", i, etCalib[i]);
|
|
for (int i = 0; i < divEdge.Length; i++) log.FatalFormat(" divEdge[{0}] = {1}", i, divEdge[i]);
|
|
for (int i = 0; i < balanceRange.Length; i++) log.FatalFormat(" balanceRange[{0}] = {1}", i, balanceRange[i]);
|
|
|
|
//#if (DN100)
|
|
ctrlBrdComponent.ExternalCom = true;
|
|
//#endif
|
|
ctrlBrdComponent.SendCalibData(rvCalib, meretA, (byte)usedCom, tempCalib, etCalib, divEdge, balanceRange);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Control of regulating valves.
|
|
/// </summary>
|
|
/// <param name="valveNo">Regulating 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)
|
|
{
|
|
if (Program.MainWnd.InvokeRequired)
|
|
{
|
|
/// When ValveMove(...) called from the worker thread
|
|
object[] args = new object[] { valveNo, valveMode, valveValue, stableTime };
|
|
Program.MainWnd.Invoke((ValveMoveDlgt)DoValveMove, args); /// When ValveMove called from a worker thread
|
|
}
|
|
else
|
|
{
|
|
/// When ValveMove(...) called from the UI thread
|
|
DoValveMove(valveNo, valveMode, valveValue, stableTime); /// When ValveMove called from the UI thread
|
|
}
|
|
}
|
|
///
|
|
delegate void ValveMoveDlgt(int valveNo, RegulValveMode valveMode, float[] valveValue, int stableTime);
|
|
///
|
|
private void DoValveMove(int valveNo, RegulValveMode valveMode, float[] valveValue, int stableTime)
|
|
{
|
|
//TBF.UiBridge.Bridge.OnLog(this, string.Format("{0} ValveMove({1}, {2}, [{3}, {4}])\r\n",
|
|
// DateTime.Now.ToLongTimeString(),
|
|
// valveNo,
|
|
// valveMode,
|
|
// valveValue[0],
|
|
// valveValue[1]));
|
|
log.InfoFormat("ValveMove(#={0}, md={1}, [{2}, {3}])", valveNo, valveMode, valveValue[0], valveValue[1]);
|
|
#if DN100 || MUNICH || FUZHOU150
|
|
ctrlBrdComponent.ValveMove((byte)valveNo, (byte)valveMode, valveValue);
|
|
#else /// all newer benches
|
|
ctrlBrdComponent.ValveMove((byte)valveNo, (byte)valveMode, valveValue, stableTime);
|
|
#endif
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Sends a command to the control board.
|
|
/// </summary>
|
|
/// <param name="cmd">See ControlBoard.Command enum</param>
|
|
/// <param name="refFlowMeterNr">Reference flow meter number (1..5)</param>
|
|
/// <param name="route">Route: 64-bit installation specific number</param>
|
|
/// <param name="refPulses">Test duration as a number of reference flow meter pulses</param>
|
|
/// <param name="testMethods">See ControlBoard.TestMethods enum</param>
|
|
/// <param name="filterConstant">0 = No filtering (0..255)</param>
|
|
/// <param name="FMFreq">Freq.inverter control (not applicable in DT100, Munich)</param>
|
|
/// <param name="regConst">Coefficient used to control the regulation valve (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 refFlowMeterNr, ulong route,
|
|
int totalRefPulses, int massRefPulses, TestMethods testMethods,
|
|
float filterConstant, float[] fmFreq, int regConst, int shortImp, StopDevs stopDevs)
|
|
{
|
|
if (Program.MainWnd.InvokeRequired)
|
|
{
|
|
/// When SendCommand(...) called from the worker thread
|
|
object[] args = new object[] { cmd, refFlowMeterNr, route, totalRefPulses, massRefPulses,
|
|
testMethods, filterConstant, fmFreq, regConst, shortImp, stopDevs };
|
|
Program.MainWnd.Invoke((SendCommandDlgt)DoSendCommand, args); /// Component was created in UI thread - use Invoke()
|
|
}
|
|
else
|
|
{
|
|
/// When SendCommand(...) called from the UI thread
|
|
DoSendCommand(cmd, refFlowMeterNr, route, totalRefPulses, massRefPulses, testMethods,
|
|
filterConstant, fmFreq, regConst, shortImp, stopDevs);
|
|
}
|
|
}
|
|
///
|
|
delegate void SendCommandDlgt(Command cmd, int refFlowmtrNr, ulong route,
|
|
int totalRefPulses, int massRefPulses, TestMethods testMethods,
|
|
float filterConstant, float[] fmFreq, int regConst, int shortImp, StopDevs stopDevs);
|
|
///
|
|
private void DoSendCommand(Command cmd, int refFlowMeterNr, ulong route,
|
|
int totalRefPulses, int massRefPulses, TestMethods testMethods,
|
|
float filterConstant, float[] fmFreq, int regConst, int shortImp, StopDevs stopDevs)
|
|
{
|
|
//TBF.UiBridge.Bridge.OnLog(this, string.Format("{0} SendCommand({1}, {2}, {3}, {4}, {5}, {6}, [{7},{8}], {9}, {10}, {11})\r\n",
|
|
// DateTime.Now.ToLongTimeString(),
|
|
// cmd,
|
|
// refFlowMeterNr,
|
|
// route.ToString("X"),
|
|
// totalRefPulses,
|
|
// testMethods,
|
|
// filterConstant,
|
|
// fmFreq[0],
|
|
// fmFreq[1],
|
|
// regConst,
|
|
// shortImp,
|
|
// stopDevs));
|
|
|
|
#if FUZHOU300
|
|
///
|
|
/// The following code deals with the situation that all FM controlled pums share bit #39.
|
|
/// In settings the bits of pumps should be sent as follows: P1=50, P2=51, P3=52, P4=53, P5=54 and P7=55
|
|
/// (in FUZHOU300 the FM pump bit should be set set to value FMIndex+50).
|
|
///
|
|
bool bit39 = (route & 0x00FC000000000000) != 0; /// true if any of bits 50 through 55 is set
|
|
route = route & 0xFF03FFFFFFFFFFFF;
|
|
if (bit39) route = route | 0x0000008000000000;
|
|
log.DebugFormat("SendCommand route = {0}", Utils.ShowRoute(route));
|
|
#endif
|
|
log.InfoFormat("SendCommand(Cmd={0},Ref#={1},Route={2} {3} {4} {5},TotalPls={6},MassPls={7},TstM={8},filt={9},FM=[{10}{11}{12}{13}{14}{15}],Reg={16},ShrtImp={17},Stop={18})",
|
|
cmd, refFlowMeterNr, /// 0, 1
|
|
((route >> 48) & 0xFFFF).ToString("X4"), /// 2
|
|
((route >> 32) & 0xFFFF).ToString("X4"), /// 3
|
|
((route >> 16) & 0xFFFF).ToString("X4"), /// 4
|
|
(route & 0xFFFF).ToString("X4"), /// 5
|
|
totalRefPulses, massRefPulses, testMethods, filterConstant, /// 6, 7, 8, 9
|
|
fmFreq[0].ToString(), /// 10
|
|
(fmFreq.Length > 1) ? ("," + fmFreq[1].ToString()) : "", /// 11
|
|
(fmFreq.Length > 2) ? ("," + fmFreq[2].ToString()) : "", /// 12
|
|
(fmFreq.Length > 3) ? ("," + fmFreq[3].ToString()) : "", /// 13
|
|
(fmFreq.Length > 4) ? ("," + fmFreq[4].ToString()) : "", /// 14
|
|
(fmFreq.Length > 5) ? ("," + fmFreq[5].ToString()) : "", /// 15
|
|
regConst, shortImp, stopDevs); /// 16, 17, 18
|
|
|
|
#if DN100 || MUNICH
|
|
ctrlBrdComponent.SendCommand((uint)cmd, (byte)refFlowMeterNr, (ulong)route, (uint)totalRefPulses, (uint)testMethods,
|
|
filterConstant, fmFreq[0], (uint)regConst, (uint)shortImp, (uint)stopDevs);
|
|
#elif BADGER_MALA_TRAT || BADGER_VELKA_TRAT || FUZHOU40 || FUZHOU150 || FUZHOU300 || PT200IL || PUCHONG_PT200 || TORINO50 || TORUN_PT50_2015 || CEVAK_PT40_272 || MURES_PT40 || GENESIS
|
|
ctrlBrdComponent.SendCommand((uint)cmd, (byte)refFlowMeterNr, (ulong)route, (uint)totalRefPulses, (uint)testMethods,
|
|
filterConstant, fmFreq, (uint)regConst, (uint)shortImp, (uint)stopDevs);
|
|
#else /// if IPERLST || IPERLST_SPECIAL || MALTA_WSD25 || SLM_50 || SLM_END || WARSAW_END
|
|
uint[] pulsesArr = new uint[] { (uint)totalRefPulses, (uint)massRefPulses };
|
|
ctrlBrdComponent.SendCommand((uint)cmd, (byte)refFlowMeterNr, (ulong)route, pulsesArr, (uint)testMethods,
|
|
filterConstant, fmFreq, (uint)regConst, (uint)shortImp, (uint)stopDevs);
|
|
#endif
|
|
|
|
ulong bufferedRoute = route;
|
|
if (lastRoute != bufferedRoute)
|
|
{
|
|
string routeStr = bufferedRoute.ToString("x16");
|
|
log.InfoFormat("DoSendCommand() Route = {0}", routeStr);
|
|
Program.MainWnd.UpdateRoute(routeStr);
|
|
lastRoute = bufferedRoute;
|
|
}
|
|
}
|
|
|
|
|
|
enum CommType
|
|
{
|
|
Rx, /// Receive data only
|
|
TxRx, /// Transmit and receive data
|
|
}
|
|
|
|
|
|
private StatusP lastStatusP;
|
|
private ulong lastRoute;
|
|
|
|
public void RunDeviceBefore()
|
|
{
|
|
object[] args = new object[] { CommType.Rx };
|
|
MakeCommDlgt dlgt = MakeComm;
|
|
Program.MainWnd.Invoke(dlgt, args); /// Invoke MakeExtComm(.) in the UI thread
|
|
|
|
StatusP bufferedStatusP = StatusP;
|
|
if (lastStatusP != bufferedStatusP)
|
|
{
|
|
string statusPStr = ((ulong)bufferedStatusP).ToString("x16");
|
|
log.InfoFormat("RunDeviceBefore() StatusP = {0}", statusPStr);
|
|
Program.MainWnd.UpdateStatusP(statusPStr);
|
|
lastStatusP = bufferedStatusP;
|
|
}
|
|
}
|
|
|
|
public void RunDeviceAfter()
|
|
{
|
|
object[] args = new object[] { CommType.TxRx };
|
|
MakeCommDlgt dlgt = MakeComm;
|
|
Program.MainWnd.Invoke(dlgt, args); /// Invoke MakeExtComm(.) in the UI thread
|
|
|
|
StatusP bufferedStatusP = StatusP;
|
|
if (lastStatusP != bufferedStatusP)
|
|
{
|
|
string statusPStr = ((ulong)bufferedStatusP).ToString("x16");
|
|
log.InfoFormat("RunDeviceAfter() StatusP = {0}", statusPStr);
|
|
Program.MainWnd.UpdateStatusP(statusPStr);
|
|
lastStatusP = bufferedStatusP;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A delegate to execute the SendCommand() in the UI thread
|
|
/// </summary>
|
|
delegate void MakeCommDlgt(CommType extComm);
|
|
|
|
/// <summary>
|
|
/// Executes the SendCommand(...) and MakeExtCom() in the UI thread
|
|
/// </summary>
|
|
void MakeComm(CommType commType)
|
|
{
|
|
if (ctrlBrdComponent.ExternalCom)
|
|
{
|
|
ctrlBrdComponent.MakeExtCom((commType == CommType.Rx) ? false : true);
|
|
}
|
|
}
|
|
}
|
|
}
|