tbf/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs
2020-01-22 13:51:47 +01:00

2736 lines
122 KiB
C#

///
/// Copyright (c) 2015-2019 Sensus Slovensko a.s.
///
//#define VERIFY_ACTIVE_MODE
//#define VERIFY_Q2_CORR_RESET
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using log4net;
using Config;
using Config.Entities;
using TBF.Resources;
using TBF.BenchControl.Sequences;
using TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead;
namespace TBF.BenchControl.TestMethods.iPerlCommunication
{
public enum CommErr
{
None = 0,
CommFailed, /// 1
OpenPort, /// 2
Read, /// 3
Read1, /// 4
Read2, /// 5
Read3, /// 6
Read4, /// 7
Write, /// 8
ReadAfterWrite, /// 9
CmdActive, /// A = 10
CmdTest, /// B = 11
Verify, /// C = 12
WrongIPerlType, /// D = 13
OutOfRange, /// E = 14
Q2OutOfRange, /// F = 15
MissingTest, /// 10H = 16
RFPowerRecordMissing, /// 11H = 17
HeadDisabledByUser, /// 12H = 18
WrongArguments, /// 13H = 19
}
public partial class iPerlCommunicationForm : Form, GenericDevices.IHasCompleted
{
private static readonly ILog log = LogManager.GetLogger(typeof(iPerlCommunicationForm));
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
const int Hz2CorrFactorsAddr = 0x1875; /// Used by Reset2HzCorrection(...) and Write2HzCorrection(...)
const int Q2CorrFactorsAddr = 0x1878; /// Used by ResetQ2Correction(...) and WriteQ2Correction(...)
const int Q2CorrFactorsAddrLR = 0x1878;
const int Q2CorrFactorsAddrRL = 0x1879;
public const string ReadConfigurationStr = "Read configuration"; /// Example: "Read configuration" or "Read configuration if enabled"
public const string SetTestModeStr = "Set Test mode"; /// Example: "Set Test mode" or "Set Test mode A0" (hexadecimal number is the required 'testModeConfig'
public const string SetActiveModeStr = "Set Active mode";
public const string ReadCalibrationStr = "Read calibration";
public const string ReadCalibrationV4Str = "Read calibration_V4";
public const string WriteCalibrationFactorStr = "Write calibration factor";
public const string WriteCalibrationV4FactorsStr = "Write calibration_V4";
public const string NormalizeCalibrationFactorStr = "Normalize calibration factor";
public const string NormalizeCalibrationV4FactorsStr = "Normalize calibration_V4";
public const string ReadQ2CorrectionStr = "Read Q2 corrections";
public const string ResetQ2CorrectionStr = "Reset Q2 correction";
public const string InitOrReadQ2CorrectionStr = "Init or read Q2 corrections";
public const string WriteQ2CorrectionStr = "Write Q2 correction"; /// No arguments
public const string WriteQ2CorrectionAltStr = "Write Q2 correction Alt"; /// No arguments
public const string WriteQ2CorrectionGreeceStr = "Write Q2 correction Greece"; /// Arguments: test_name
public const string WriteQ2CorrectionRLStr = "Write Q2 correction R-L"; /// Arguments: test_name
public const string WriteQ2CorrectionLRStr = "Write Q2 correction L-R"; /// Arguments: test_name
public const string UpdateQ2CorrectionsStr = "Update Q2 corrections"; /// Arguments: R-L_test_name L-R_test_name
public const string ConditnlUpdateQ2CorrectionsStr = "Conditional update of Q2 corrections"; /// Arguments: R-L_test_name L-R_test_name
public const string Reset2HzCorrectionStr = "Reset 2Hz correction";
public const string Write2HzCorrectionStr = "Write 2Hz correction";
public static Color DisabledColor = Color.DarkGray;
public static Color OptoAndDirOKColor = Color.Green;
public static Color OptoNokColor = Color.Orange;
public static Color DirNokColor = Color.Red;
#region DLL_Interface
[DllImport("libRfid1.dll", EntryPoint = "getDllVersion")] static extern unsafe int getDllVersion1();
[DllImport("libRfid1.dll", EntryPoint = "openPort")] static extern unsafe int openPort1(int comPort);
[DllImport("libRfid1.dll", EntryPoint = "closePort")] static extern unsafe int closePort1();
[DllImport("libRfid1.dll", EntryPoint = "readRequestPort")] static extern unsafe int readRequestPort1(MessageID messageId, int offset, int lenght, byte* ptr, int timeout_ms);
[DllImport("libRfid1.dll", EntryPoint = "writeRequestPort")] static extern unsafe int writeRequestPort1(MessageID messageId, int offset, int lenght, byte* ptr, int timeout_ms);
[DllImport("libRfid2.dll", EntryPoint = "getDllVersion")] public static extern unsafe int getDllVersion2();
[DllImport("libRfid2.dll", EntryPoint = "openPort")] static extern unsafe int openPort2(int comPort);
[DllImport("libRfid2.dll", EntryPoint = "closePort")] static extern unsafe int closePort2();
[DllImport("libRfid2.dll", EntryPoint = "readRequestPort")] static extern unsafe int readRequestPort2(MessageID messageId, int offset, int lenght, byte* ptr, int timeout_ms);
[DllImport("libRfid2.dll", EntryPoint = "writeRequestPort")] static extern unsafe int writeRequestPort2(MessageID messageId, int offset, int lenght, byte* ptr, int timeout_ms);
[DllImport("libRfid3.dll", EntryPoint = "getDllVersion")] public static extern unsafe int getDllVersion3();
[DllImport("libRfid3.dll", EntryPoint = "openPort")] static extern unsafe int openPort3(int comPort);
[DllImport("libRfid3.dll", EntryPoint = "closePort")] static extern unsafe int closePort3();
[DllImport("libRfid3.dll", EntryPoint = "readRequestPort")] static extern unsafe int readRequestPort3(MessageID messageId, int offset, int lenght, byte* ptr, int timeout_ms);
[DllImport("libRfid3.dll", EntryPoint = "writeRequestPort")] static extern unsafe int writeRequestPort3(MessageID messageId, int offset, int lenght, byte* ptr, int timeout_ms);
[DllImport("libRfid4.dll", EntryPoint = "getDllVersion")] public static extern unsafe int getDllVersion4();
[DllImport("libRfid4.dll", EntryPoint = "openPort")] static extern unsafe int openPort4(int comPort);
[DllImport("libRfid4.dll", EntryPoint = "closePort")] static extern unsafe int closePort4();
[DllImport("libRfid4.dll", EntryPoint = "readRequestPort")] static extern unsafe int readRequestPort4(MessageID messageId, int offset, int lenght, byte* ptr, int timeout_ms);
[DllImport("libRfid4.dll", EntryPoint = "writeRequestPort")] static extern unsafe int writeRequestPort4(MessageID messageId, int offset, int lenght, byte* ptr, int timeout_ms);
/// <summary>
/// Wrapper function with safe interface and unsafe body
/// </summary>
/// <param name="threadID">0..3</param>
/// <param name="iperlHead">Water meter (iPerlHead) object</param>
/// <returns>Value returned by openPort(...)</returns>
public static unsafe int OpenPort(int threadID, IperlHead iperlHead)
{
if (iperlHead.DebugLevel != DebugMode.Normal) return 0; /// No function in debug mode
int rfidPortNr;
if (cfg.UseMuxBoards)
{
switch (iperlHead.MuxBoardNrOrGroup14)
{
default:
case 1: rfidPortNr = cfg.RfidPortNrBoard1; break;
case 2: rfidPortNr = cfg.RfidPortNrBoard2; break;
case 3: rfidPortNr = cfg.RfidPortNrBoard3; break;
case 4: rfidPortNr = cfg.RfidPortNrBoard4; break;
}
}
else
{
rfidPortNr = iperlHead.RfidComPortNr;
}
switch (threadID)
{
default:
case 0: return openPort1(rfidPortNr);
case 1: return openPort2(rfidPortNr);
case 2: return openPort3(rfidPortNr);
case 3: return openPort4(rfidPortNr);
}
}
/// <summary>
/// Wrapper function with safe interface and unsafe body
/// </summary>
/// <param name="threadID">0..3</param>
/// <param name="iperlHead">Water meter (iPerlHead) object</param>
/// <returns>Value returned by openPort(...)</returns>
public static unsafe int ClosePort(int threadID, IperlHead iperlHead)
{
if (iperlHead.DebugLevel != DebugMode.Normal) return 0; /// No function in debug mode
switch (threadID)
{
default:
case 0: return closePort1();
case 1: return closePort2();
case 2: return closePort3();
case 3: return closePort4();
}
}
/// <summary>
/// Wrapper function with safe interface and unsafe body
/// </summary>
/// <param name="threadID">0..3</param>
/// <param name="iperlHead">Water meter (iPerlHead) object</param>
/// <returns>Value returned by readRequestPort(...)</returns>
public static unsafe int ReadRequestPort(int threadID, IperlHead iperlHead, MessageID messageID, int offset, int length, out byte[] buffer, int timeout)
{
if (iperlHead.DebugLevel != DebugMode.Normal)
{
///
/// Simulation
///
if ((messageID == MessageID.Configuration) && (offset == 0) && (length == ConfigStruct.Length))
{
buffer = new byte[ConfigStruct.Length] { 3, 3, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0, 1,2,3,4,5, 160, 0,0,0,0, 0,0, 0,0, 0,0 };
}
else if ((messageID == MessageID.Calibration) && (offset == 0) && (length == CalibrationStruct.Length))
{
buffer = new byte[CalibrationStruct.Length] { 3, 0, 150,10, 0, 0, 0,0, 0,0,0,0,0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,0,0, 1,2,3,4,5, 0, 0 };
}
else if ((messageID == MessageID.Calibration) && (offset == 0) && (length == CalibrationStructV4.Length))
{
buffer = new byte[CalibrationStructV4.Length] { 3, 0, 150,10, 0, 0, 0,0, 0,0,0,0,0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,0,0, 1,2,3,4,5, 0, 0, 150,10 };
}
else if ((messageID == MessageID.Calibration) && (offset == 2) && (length == 2))
{
buffer = new byte[2] { 150,10 };
}
else if ((messageID == MessageID.Calibration) && (offset == 34) && (length == 2))
{
buffer = new byte[2] { 150,10 };
}
else if ((messageID == MessageID.MetrologyMemory) && (offset == Q2CorrFactorsAddr) && (length == 2))
{
buffer = new byte[2] { 0, 0 };
}
else
{
buffer = new byte[length];
}
return iperlHead.Name.Equals("iPerl13") ? 2 : 0; /// Simulates an error on position 13
}
buffer = new byte[length];
byte[] buf = new byte[200];
///
fixed (byte* pBuf = buf)
{
int retv;
switch (threadID)
{
default:
case 0: retv = readRequestPort1(messageID, offset, length, pBuf, timeout); break;
case 1: retv = readRequestPort2(messageID, offset, length, pBuf, timeout); break;
case 2: retv = readRequestPort3(messageID, offset, length, pBuf, timeout); break;
case 3: retv = readRequestPort4(messageID, offset, length, pBuf, timeout); break;
}
for (int i = 0; i < length; i++) buffer[i] = buf[i];
///
/// Logging
///
string name = string.Format("{0}({1})", iperlHead.Name, iperlHead.SerialNr);
if ((messageID == MessageID.Configuration) && (offset == 0) && (length == ConfigStruct.Length))
rfidDataLogger.InfoFormat("{0}: ReadRequestPort({1},...) returned {2} {3}", name, messageID, retv, (retv != 0) ? "!" : ConfigStruct.FromByteArray(buffer).ToString());
else if ((messageID == MessageID.Calibration) && (offset == 0) && (length == CalibrationStruct.Length))
rfidDataLogger.InfoFormat("{0}: ReadRequestPort({1},...) returned {2} {3}", name, messageID, retv, (retv != 0) ? "!" : CalibrationStruct.FromByteArray(buffer).ToString());
else if ((messageID == MessageID.Calibration) && (offset == 0) && (length == CalibrationStructV4.Length))
rfidDataLogger.InfoFormat("{0}: ReadRequestPort({1},...) returned {2} {3}", name, messageID, retv, (retv != 0) ? "!" : CalibrationStructV4.FromByteArray(buffer).ToString());
else if ((messageID == MessageID.Calibration) && (offset == 2) && (length == 2))
rfidDataLogger.InfoFormat("{0}: ReadRequestPort({1},2,2,...) returned {2} {3}", name, messageID, retv, (retv != 0) ? "!" : string.Format("Cal={0}", buf[0] + 256 * buf[1]));
else if ((messageID == MessageID.Calibration) && (offset == 34) && (length == 2))
rfidDataLogger.InfoFormat("{0}: ReadRequestPort({1},34,2,...) returned {2} {3}", name, messageID, retv, (retv != 0) ? "!" : string.Format("CalLNA={0}", buf[0] + 256 * buf[1]));
else if ((messageID == MessageID.MetrologyMemory) && (offset == Q2CorrFactorsAddr) && (length == 2))
rfidDataLogger.InfoFormat("{0}: ReadRequestPort({1},6264,2,...) returned {2} {3}", name, messageID, retv, (retv != 0) ? "!" : string.Format("LR={0} RL={1}", (int)buf[0], (int)buf[1]));
else
rfidDataLogger.InfoFormat("{0}: ReadRequestPort({1}, {2}, {3}, ...) returned {4} {5}", name, messageID, offset, length, retv, (retv != 0) ? "!" : "");
return retv;
}
}
/// <summary>
/// Wrapper function with safe interface adn unsafe body
/// </summary>
/// <param name="threadID">0..3</param>
/// <param name="iperlHead">Water meter (iPerlHead) object</param>
/// <returns>Value returned by writeRequestPort(...)</returns>
public static unsafe int WriteRequestPort(int threadID, IperlHead iperlHead, MessageID messageID, int offset, int length, byte[] buffer, int timeout)
{
if (iperlHead.DebugLevel != DebugMode.Normal) return 0;
fixed (byte* pBuf = buffer)
{
int retv;
switch (threadID)
{
default:
case 0: retv = writeRequestPort1(messageID, offset, length, pBuf, timeout); break;
case 1: retv = writeRequestPort2(messageID, offset, length, pBuf, timeout); break;
case 2: retv = writeRequestPort3(messageID, offset, length, pBuf, timeout); break;
case 3: retv = writeRequestPort4(messageID, offset, length, pBuf, timeout); break;
}
/// Delay min. 250 ms
Thread.Sleep(Math.Max(250, cfg.DelayBetweenRetries));
///
/// Logging
///
string name = string.Format("{0}({1})", iperlHead.Name, iperlHead.SerialNr);
if (length == 1)
rfidDataLogger.InfoFormat("{0}: WriteRequestPort({2}, {3}, {4}, {5}) returned {1} {6}", name, retv, messageID, offset, length, pBuf[0].ToString("X2"), (retv != 0) ? "!" : "");
else if (length == 2)
{
if (messageID == MessageID.Calibration && offset == 2)
{
UInt16 calibFactor = (UInt16)(pBuf[0] + 256 * pBuf[1]);
rfidDataLogger.InfoFormat("{0}: WriteRequestPort(Cal={1}) returned {2} {3}", name, calibFactor, retv, (retv != 0) ? "!" : "");
}
else if (messageID == MessageID.Calibration && offset == 34)
{
UInt16 calibFactor = (UInt16)(pBuf[0] + 256 * pBuf[1]);
rfidDataLogger.InfoFormat("{0}: WriteRequestPort(CalLNA={1}) returned {2} {3}", name, calibFactor, retv, (retv != 0) ? "!" : "");
}
else
rfidDataLogger.InfoFormat("{0}: WriteRequestPort({2}, {3}, {4}, {5} {6}) returned {1} {7}", name, retv, messageID, offset, length, pBuf[0].ToString("X2"), pBuf[1].ToString("X2"), (retv != 0) ? "!" : "");
}
else
rfidDataLogger.InfoFormat("{0}: WriteRequestPort({2}, {3}, {4}, {5} {6} ...) returned {1} {7}", name, retv, messageID, offset, length, pBuf[0].ToString("X2"), pBuf[1].ToString("X2"), (retv != 0) ? "!" : "");
return retv;
}
}
#endregion DLL_Interface
readonly bool checkBoxesEditMode;
DateTime startTime;
int startTimeSec;
// Set to 'true' when the form closes
public bool Completed { get { return formCompleted; } }
bool formCompleted;
bool forcedClose; /// Set in the forced close handler
/// <summary> Number of text boxes for serial numbers </summary>
public int WaterMetersCount;
const int MaxTextBoxesCount = 48;
int textBoxesCount;
Label[] labels;
PictureBox[] counters;
TextBox[] messages;
CheckBoxImage[] checkBoxes;
static int[] ckbIndex;
static bool[] ckbState;
static IList<IperlHead> iperlHeads;
static IList<int> waterMeterPositions0; /// keeps original 0-based indices in RegisterReaders list
Modbus.QuidoRS.QuidoRS quido;
///
/// RFID multiplexer PCB / RFID serial port and worker thread related variables
///
static TestMethodCfg cfg;
static IList<Config.Entities.Test> tests;
static IList<iPerlCommunicationParams> multiTestParams;
static int currentActivityStep;
static int currentGroup; /// form -> worker thread (0 = none)
static int lastGroup;
static int completedCommCount; /// Number of completed communication steps
static IList<Thread> workerThreads;
static IList<int> muxBrdOrGroup14Nrs;
static bool stopWorkerThreads; /// form -> worker thread
/// <summary> Parameterless constructor (without watermeters, threads) </summary>
public iPerlCommunicationForm()
{
InitializeComponent();
}
/// <summary>
/// Constructor for checkBox states (active/inactive iPerl head) editing.
/// </summary>
/// <param name="checkBoxes">Initial check box states</param>
public iPerlCommunicationForm(bool isCheckBoxesEditMode)
: this()
{
if (isCheckBoxesEditMode)
{
checkBoxesEditMode = true;
saveButton.Visible = true;
activityLabel.Text = Strings.Activate_Deactivate_heads;
ShuffleTextBoxes(Config.Data.WMsCount, Config.Data.LineSize);
}
}
/// <summary>
/// Constructor for one iPerlCommunication 'test'
/// </summary>
/// <param name="waterMetersCount">Number of text boxes for serial numbers</param>
public iPerlCommunicationForm(TestMethodCfg cfg, Test test, iPerlCommunicationParams testParams)
: this(cfg, new List<Test> { test }, new List<iPerlCommunicationParams> { testParams })
{
}
/// <summary>
/// Constructor for multiple iPerlCommunication 'tests'
/// </summary>
/// <param name="waterMetersCount">Number of text boxes for serial numbers</param>
public iPerlCommunicationForm(TestMethodCfg cfg, IList<Test> tests, IList<iPerlCommunicationParams> multiTestParams)
: this()
{
checkBoxesEditMode = false;
iPerlCommunicationForm.cfg = cfg;
iPerlCommunicationForm.tests = tests;
iPerlCommunicationForm.multiTestParams = multiTestParams;
if (multiTestParams.Count > 0)
{
ProcessData.RegisterReaders = StateMachine.GetMetersPath(tests[0]).RegisterReaders;
activityLabel.Text = multiTestParams[0].Activity;
}
ConstructorCommon();
}
void ConstructorCommon()
{
startTime = DateTime.Now;
startTimeSec = StateMachine.Time;
/// Find QuidoRS
quido = null;
if (StateMachine.Components != null)
{
foreach (var comp in StateMachine.Components)
{
Modbus.QuidoRS.QuidoRS q = comp as Modbus.QuidoRS.QuidoRS;
if ((q != null) && (q.Variant == Modbus.QuidoRS.QuidoVariant.QuidoRS_2_16))
{
quido = q;
break;
}
}
}
/// Attach to 'CommCompleted' handler
CommCompletedHandler += delegate(object sender, CommCompletedEventArgs args)
{
if (InvokeRequired)
{
Invoke(new EventHandler<CommCompletedEventArgs>(DoOnCommCompleted), sender, args);
}
else DoOnCommCompleted(sender, args);
};
/// Attach to 'AllCompleted' handler
AllCompletedHandler += delegate(object sender, AllCompletedEventArgs args)
{
if (InvokeRequired)
{
Invoke(new EventHandler<AllCompletedEventArgs>(DoOnAllCompleted), sender, args);
}
else DoOnAllCompleted(sender, args);
};
formCompleted = false;
StartForceCloseHandler();
iperlHeads = new List<IperlHead>();
waterMeterPositions0 = new List<int>();
///
for (int wmPos = 0; wmPos < ProcessData.RegisterReaders.Length; wmPos++)
{
IperlHead iperlHead = ProcessData.RegisterReaders[wmPos] as IperlHead;
if (iperlHead != null)
{
iperlHeads.Add(iperlHead);
waterMeterPositions0.Add(wmPos);
}
}
WaterMetersCount = iperlHeads.Count;
ShuffleTextBoxes(WaterMetersCount, Config.Data.LineSize);
///
/// Prepare worker threads, 'rfidPortNrs', 'lastGroup', etc..
///
currentActivityStep = 0;
currentGroup = 0;
completedCommCount = 0;
stopWorkerThreads = false;
/// group numbers are >=1, lastGroup == 0 means there is no group
lastGroup = 0;
foreach (var iPerl in iPerlCommunicationForm.iperlHeads)
{
if (iPerl.Group > lastGroup) lastGroup = iPerl.Group;
}
workerThreads = new List<Thread>();
for (int i = 0; i < cfg.NrThreads; i++)
{
Thread thread = new Thread(iPerlCommunicationForm.Worker);
thread.CurrentCulture = CultureInfo.CurrentCulture;
thread.CurrentUICulture = CultureInfo.CurrentUICulture;
workerThreads.Add(thread);
}
muxBrdOrGroup14Nrs = new List<int>();
foreach (var iPerl in iPerlCommunicationForm.iperlHeads)
{
if (!muxBrdOrGroup14Nrs.Contains(iPerl.MuxBoardNrOrGroup14)) muxBrdOrGroup14Nrs.Add(iPerl.MuxBoardNrOrGroup14);
}
StringBuilder sb = new StringBuilder();
if (cfg.UseMuxBoards)
{
sb.Append("rfidPortNrs = [");
foreach (var v in muxBrdOrGroup14Nrs) sb.Append(string.Format(" {0}", v));
sb.Append(" ], ");
}
sb.Append(string.Format("nrThreads = {0}", workerThreads.Count));
log.WarnFormat(sb.ToString());
}
/// <summary>
/// Make sure the layout of labels/text boxes on the screen
/// corresponds to the layout of watermeters of the test bench.
/// </summary>
/// <param name="wmsCount">Number of watermeters</param>
/// <param name="lineSize">Number of watermeters in one line</param>
void ShuffleTextBoxes(int wmsCount, int lineSize)
{
labels = new Label[MaxTextBoxesCount]
{
wmLabel1, wmLabel2, wmLabel3, wmLabel4, wmLabel5, wmLabel6, wmLabel7, wmLabel8, wmLabel9, wmLabel10,
wmLabel11, wmLabel12, wmLabel13, wmLabel14, wmLabel15, wmLabel16, wmLabel17, wmLabel18, wmLabel19, wmLabel20,
wmLabel21, wmLabel22, wmLabel23, wmLabel24, wmLabel25, wmLabel26, wmLabel27, wmLabel28, wmLabel29, wmLabel30,
wmLabel31, wmLabel32, wmLabel33, wmLabel34, wmLabel35, wmLabel36, wmLabel37, wmLabel38, wmLabel39, wmLabel40,
wmLabel41, wmLabel42, wmLabel43, wmLabel44, wmLabel45, wmLabel46, wmLabel47, wmLabel48,
};
counters = new PictureBox[MaxTextBoxesCount]
{
pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6, pictureBox7, pictureBox8, pictureBox9, pictureBox10,
pictureBox11, pictureBox12, pictureBox13, pictureBox14, pictureBox15, pictureBox16, pictureBox17, pictureBox18, pictureBox19, pictureBox20,
pictureBox21, pictureBox22, pictureBox23, pictureBox24, pictureBox25, pictureBox26, pictureBox27, pictureBox28, pictureBox29, pictureBox30,
pictureBox31, pictureBox32, pictureBox33, pictureBox34, pictureBox35, pictureBox36, pictureBox37, pictureBox38, pictureBox39, pictureBox40,
pictureBox41, pictureBox42, pictureBox43, pictureBox44, pictureBox45, pictureBox46, pictureBox47, pictureBox48,
};
messages = new TextBox[MaxTextBoxesCount]
{
wmTextBox1, wmTextBox2, wmTextBox3, wmTextBox4, wmTextBox5, wmTextBox6, wmTextBox7, wmTextBox8, wmTextBox9, wmTextBox10,
wmTextBox11, wmTextBox12, wmTextBox13, wmTextBox14, wmTextBox15, wmTextBox16, wmTextBox17, wmTextBox18, wmTextBox19, wmTextBox20,
wmTextBox21, wmTextBox22, wmTextBox23, wmTextBox24, wmTextBox25, wmTextBox26, wmTextBox27, wmTextBox28, wmTextBox29, wmTextBox30,
wmTextBox31, wmTextBox32, wmTextBox33, wmTextBox34, wmTextBox35, wmTextBox36, wmTextBox37, wmTextBox38, wmTextBox39, wmTextBox40,
wmTextBox41, wmTextBox42, wmTextBox43, wmTextBox44, wmTextBox45, wmTextBox46, wmTextBox47, wmTextBox48,
};
checkBoxes = new CheckBoxImage[MaxTextBoxesCount]
{
checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5, checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10,
checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15, checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20,
checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25, checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30,
checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35, checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40,
checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45, checkBoxImage46, checkBoxImage47, checkBoxImage48,
};
ckbIndex = new int[MaxTextBoxesCount];
ckbState = new bool[MaxTextBoxesCount];
textBoxesCount = MaxTextBoxesCount;
///
if (wmsCount < textBoxesCount && lineSize > 0)
{
int nrLines = (wmsCount + lineSize - 1) / lineSize;
int gap = (textBoxesCount - wmsCount) / nrLines;
int dest = 0;
for (int l = 0; l < nrLines; l++)
{
for (int i = 0; i < lineSize; i++)
{
labels[dest] = labels[l * lineSize + l * gap + i];
counters[dest] = counters[l * lineSize + l * gap + i];
messages[dest] = messages[l * lineSize + l * gap + i];
checkBoxes[dest] = checkBoxes[l * lineSize + l * gap + i];
ckbIndex[l * lineSize + l * gap + i] = dest;
dest++;
}
}
textBoxesCount = wmsCount;
}
if (checkBoxesEditMode)
{
for (int j = 0; j < textBoxesCount; j++) labels[j].Text = string.Format("iPerl{0}", j + 1);
}
else
{
for (int j = 0; j < Math.Min(textBoxesCount, iperlHeads.Count); j++) labels[j].Text = iperlHeads[j].Name;
}
ResizeDlgToFitEnabledControls();
}
void ResizeDlgToFitEnabledControls()
{
int xMax = 0;
int yMax = 0;
for (int i = 0; i < textBoxesCount; i++)
{
if (messages[i].Left + messages[i].Width > xMax) xMax = messages[i].Left + messages[i].Width;
if (messages[i].Top + messages[i].Height > yMax) yMax = messages[i].Top + messages[i].Height;
}
Width = xMax + 30;
Height = yMax + 50;
saveButton.Location = new Point(Width - 105, saveButton.Location.Y);
}
void Localize()
{
Text = Strings.Water_Meter_States;
saveButton.Text = Strings.Save;
sampleLabel1.Text = Strings.Direction_and_pulses_are_OK;
sampleLabel2.Text = Strings.There_are_no_opto_pulses;
sampleLabel3.Text = Strings.Direction_is_NOK;
samplePictureBox1.BackColor = OptoAndDirOKColor;
samplePictureBox2.BackColor = OptoNokColor;
samplePictureBox3.BackColor = DirNokColor;
}
private void iPerlCommunicationForm_Load(object sender, EventArgs e)
{
Localize();
for (int i = 0; i < textBoxesCount; i++)
{
labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = true;
if (!checkBoxesEditMode && (iperlHeads[i] == null || iperlHeads[i].Disabled))
{
checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = false;
counters[i].BackColor = DisabledColor;
messages[i].Text = Strings.Head_was_disabled_by_the_user;
}
else
{
checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = true;
messages[i].Text = "---";
}
}
TBF.LocalSettings ls = Program.LocalSettings;
Left = (ls.iPerlCommunicationsFormLeft != 0) ? ls.iPerlCommunicationsFormLeft : 150;
Top = (ls.iPerlCommunicationsFormTop != 0) ? ls.iPerlCommunicationsFormTop : 150;
if (ls.iPerlCommunicationsFormCheckboxes != 0) SetCheckBoxStates(ls.iPerlCommunicationsFormCheckboxes);
if (!checkBoxesEditMode)
{
/// Reset opto-data indication
for (int i = 0; i < iperlHeads.Count; i++)
{
counters[i].BackColor = OptoNokColor;
}
///
/// Set QuidoRS outputs and start the whole communication process
/// by incrementing 'currentGroup'.
///
if (cfg.UseMuxBoards && (quido != null))
{
quido.SetOutputs((ushort)(16 - currentGroup - 1));
Thread.Sleep(2000);
}
currentGroup++;
/// Start worker threads
int wtId = 0;
foreach (var wt in workerThreads) wt.Start(new Boxes.IntBox(wtId++));
}
}
private void NormalClose()
{
CommCompletedHandler = null;
AllCompletedHandler = null;
if (multiTestParams != null &&
multiTestParams.Count > 0 &&
!multiTestParams[0].SimultWithNext) /// RFID Communication at the end of the cycle does not influence the result
{
UpdateRfidCommResult(tests); /// TODO: Pass the test info in a correct way
}
long checkboxStates = GetCheckBoxStates();
if (Program.LocalSettings.iPerlCommunicationsFormLeft != Location.X ||
Program.LocalSettings.iPerlCommunicationsFormTop != Location.Y ||
Program.LocalSettings.iPerlCommunicationsFormCheckboxes != checkboxStates)
{
/// Update local settings
Program.LocalSettings.iPerlCommunicationsFormLeft = Location.X;
Program.LocalSettings.iPerlCommunicationsFormTop = Location.Y;
Program.LocalSettings.iPerlCommunicationsFormCheckboxes = checkboxStates;
Program.LocalSettings.Save();
}
formCompleted = true;
DialogResult = DialogResult.OK;
Close();
}
#region Forced close handling
public void StartForceCloseHandler()
{
UiBridge.Bridge.CloseModelessFormHandler += delegate(object sender, EventArgs args)
{
if (InvokeRequired) { Invoke(new EventHandler<EventArgs>(OnForceClose), sender, args); }
else OnForceClose(sender, args);
};
}
void OnForceClose(object sender, EventArgs args)
{
CommCompletedHandler = null;
AllCompletedHandler = null;
stopWorkerThreads = true;
forcedClose = true;
DialogResult = DialogResult.Cancel;
Close();
}
#endregion
/// <summary>
/// Worker thread
/// </summary>
/// <param name="threadData">Thread ID (integer) wrapped into IntBox</param>
static void Worker(object threadData)
{
int threadID = (threadData as Boxes.IntBox).Val;
int activityStep = 0; /// activity step > 0 in case multiTestParams are used
for (int i = 0; i < multiTestParams.Count; i++ )
{
Test currentTest = tests[i];
iPerlCommunicationParams currentTestParams = multiTestParams[i];
string currentActivity = currentTestParams.Activity; /// Current activity
TBF.UiBridge.TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 10, 0, 140, 0, 0, 0 });
TBF.UiBridge.Bridge.OnTestProgress(null, new TBF.UiBridge.TestProgressEventArgs(tests[i], Config.Entities.Progress.JustStarted));
if (threadID == 0)
{
rfidDataLogger.InfoFormat(""); /// Makes the log more readable when there is a lot of data
rfidDataLogger.WarnFormat("Activity = {0}", currentActivity);
rfidDataLogger.InfoFormat(""); /// Makes the log more readable when there is a lot of data
}
for (int group = 1; group <= lastGroup; group++)
{
/// Synchronize with QuidoRS and other threads
while (((group != currentGroup) || (activityStep != currentActivityStep)) && !stopWorkerThreads)
{
Thread.Sleep(50);
}
if (stopWorkerThreads) break;
#if TURA_SPECIAL
int threadIx = threadID; /// Just one thread for TURA_SPECIAL
#else
for (int threadIx = threadID; threadIx < threadID + 4; threadIx += cfg.NrThreads)
#endif
{
if (cfg.UseMuxBoards && threadIx >= muxBrdOrGroup14Nrs.Count) break; // quit, all RFID ports of all water meters done
bool wmFound = false;
for (int wmNr0 = 0; wmNr0 < iperlHeads.Count; wmNr0++)
{
IperlHead ihead = iperlHeads[wmNr0];
if ((ihead.Group == group) && (threadIx < muxBrdOrGroup14Nrs.Count) && (ihead.MuxBoardNrOrGroup14 == muxBrdOrGroup14Nrs[threadIx]))
{
wmFound = true;
Results.Entities.WaterMeter wm = ProcessData.BatchRslts.WaterMeters[waterMeterPositions0[wmNr0]];
CommErr error;
string resultStr = string.Empty;
///
/// RFID communication activity call
///
if ((ihead == null) || ihead.Disabled || !ckbState[wmNr0]) error = CommErr.HeadDisabledByUser;
else if (wm == null) error = CommErr.CommFailed;
#if IPERL
else if (currentActivity.ToLower().Contains(ReadConfigurationStr.ToLower())) error = ReadConfiguration(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Contains(SetTestModeStr.ToLower())) error = SetTestMode(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(SetActiveModeStr.ToLower())) error = SetActiveMode(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(ReadCalibrationStr.ToLower())) error = ReadCalibration(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(ReadCalibrationV4Str.ToLower())) error = ReadCalibrationV4(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Contains(WriteCalibrationFactorStr.ToLower())) error = WriteCalibrationFactor(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Contains(WriteCalibrationV4FactorsStr.ToLower())) error = WriteCalibrationV4Factors(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(NormalizeCalibrationFactorStr.ToLower())) error = NormalizeCalibrationFactor(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(NormalizeCalibrationV4FactorsStr.ToLower())) error = NormalizeCalibrationV4Factors(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(ReadQ2CorrectionStr.ToLower())) error = ReadQ2Correction(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(ResetQ2CorrectionStr.ToLower())) error = ResetQ2Correction(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(InitOrReadQ2CorrectionStr.ToLower())) error = InitOrReadQ2Correction(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(WriteQ2CorrectionStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Standard, null);
else if (currentActivity.ToLower().Equals(WriteQ2CorrectionAltStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Dewa, null);
else if (currentActivity.ToLower().Contains(WriteQ2CorrectionGreeceStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Greece, currentActivity.Substring(WriteQ2CorrectionGreeceStr.Length).Trim());
else if (currentActivity.ToLower().Contains(WriteQ2CorrectionRLStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.RL, currentActivity.Substring(WriteQ2CorrectionRLStr.Length).Trim());
else if (currentActivity.ToLower().Contains(WriteQ2CorrectionLRStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.LR, currentActivity.Substring(WriteQ2CorrectionLRStr.Length).Trim());
else if (currentActivity.ToLower().Contains(UpdateQ2CorrectionsStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.Update, currentActivity.Substring(UpdateQ2CorrectionsStr.Length).Trim());
else if (currentActivity.ToLower().Contains(ConditnlUpdateQ2CorrectionsStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, currentTest, ref resultStr, Q2CorrType.ConditionalUpdate, currentActivity.Substring(ConditnlUpdateQ2CorrectionsStr.Length).Trim());
else if (currentActivity.ToLower().Equals(Reset2HzCorrectionStr.ToLower())) error = Reset2HzCorrection(threadID, ihead, wm, ref resultStr);
else if (currentActivity.ToLower().Equals(Write2HzCorrectionStr.ToLower())) error = Write2HzCorrection(threadID, ihead, wm, ref resultStr);
#endif
else
{
error = CommErr.None;
resultStr = "Invalid activity";
}
///
/// Process the result of RFID communication activity
///
if (error == CommErr.HeadDisabledByUser || !ckbState[wmNr0])
{
OnCommCompleted(null, new CommCompletedEventArgs(threadID, wmNr0, ihead, wm, Strings.Head_was_disabled_by_the_user, CommErr.HeadDisabledByUser));
}
else if (error == CommErr.None)
{
OnCommCompleted(null, new CommCompletedEventArgs(threadID, wmNr0, ihead, wm, resultStr, CommErr.None));
}
else if ((error == CommErr.OutOfRange) || (error == CommErr.Q2OutOfRange))
{
OnCommCompleted(null, new CommCompletedEventArgs(threadID, wmNr0, ihead, wm, resultStr, CommErr.None));
}
else if (ihead.CommFailed || (error == CommErr.CommFailed))
{
ihead.CommFailed = true;
if ((wm.ResultCode & (int)Results.Entities.ResultCode.RfidErrorCodeMask) == 0)
{
wm.ResultCode |= (((int)error << 16) | ((int)tests[i].ItemNr << 20));
}
OnCommCompleted(null, new CommCompletedEventArgs(threadID, wmNr0, ihead, wm, Strings.RFID_communication_failed, error));
}
else
{
ihead.CommFailed = true;
if ((wm.ResultCode & (int)Results.Entities.ResultCode.RfidErrorCodeMask) == 0)
{
wm.ResultCode |= (((int)error << 16) | ((int)tests[i].ItemNr << 20));
}
string failureCauseLocal = string.Format(Strings.failed_0_1_exclamation, currentActivity, error);
rfidDataLogger.ErrorFormat("Group={0}, Board={1}, {2}", currentGroup, ihead.MuxBoardNrOrGroup14, failureCauseLocal);
OnCommCompleted(null, new CommCompletedEventArgs(threadID, wmNr0, ihead, wm, failureCauseLocal, error));
}
break;
}
TBF.UiBridge.Bridge.OnTestProgress(null, new TBF.UiBridge.TestProgressEventArgs(tests[i], Config.Entities.Progress.FlowSetting));
}
if (!wmFound)
{
OnCommCompleted(null, new CommCompletedEventArgs(threadID, -1, null, null, string.Empty, CommErr.None)); /// Send negative wmNr
}
if (stopWorkerThreads) break;
}
if (stopWorkerThreads) break;
} /// for (int group
TBF.UiBridge.Bridge.OnTestProgress(null, new TBF.UiBridge.TestProgressEventArgs(tests[i], Config.Entities.Progress.Completed));
activityStep++;
if (stopWorkerThreads) break;
}
}
#region Communication functions
#if IPERL
/// <summary>
/// Read a complete configuration structure of the watermeter
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr ReadConfiguration(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
///
/// The activity is "Read configuration" (this enables the watermeter, resets error flag)
/// or "Read configuration if enabled" (this keeps the error flag).
///
if (!multiTestParams[currentActivityStep].Activity.ToLower().Contains(" if enabled"))
{
ihead.CommFailed = false;
}
if (ihead.CommFailed) return CommErr.CommFailed;
ihead.ConfigStruct = null; /// Clear previous ConfigStruct, avoid reuse of (not anymore valid) PCB Number
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Read;
int readRetVal = 0;
/// Read configuration
byte[] config = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
readRetVal = ReadRequestPort(threadId, ihead, MessageID.Configuration, 0, ConfigStruct.Length, out config, cfg.CommTimeout);
if (readRetVal == 0)
{
error = CommErr.None;
ihead.ConfigStruct = ConfigStruct.FromByteArray(config);
resultStr = ihead.ConfigStruct.ToString(1);
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
ClosePort(threadId, ihead); /// Close RFID port
return error + Math.Max(0, Math.Min(readRetVal, 4));
}
/// <summary>
/// Set the watermeter to the test mode.
/// If testModeConfig is specified as a hexadeximal number appended to "set test mode ", it is verified
/// whether the testModeConfig is correctly set, if necessary it is changed to the specified value.
/// Read a part of configuration afterwards to verify the mode was set correctly.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr SetTestMode(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed || ihead.ConfigStruct == null) return CommErr.CommFailed;
Byte testModeConfig = 0xA0; /// Default value
///
if (multiTestParams[currentActivityStep].Activity.Length > SetTestModeStr.Length)
{
string testModeConfigStr = multiTestParams[currentActivityStep].Activity.Substring(SetTestModeStr.Length + 1);
UInt16 byteVal;
if (UInt16.TryParse(testModeConfigStr, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out byteVal) && byteVal <= 255)
{
testModeConfig = (Byte)byteVal; /// Update with specified value
}
}
if (ihead.ConfigStruct.MeterState == MeterState.Test && ihead.ConfigStruct.TestModeConfig == testModeConfig)
{
/// Already in the correct test mode
resultStr = "Already " + ihead.ConfigStruct.ToString(1);
return CommErr.None;
}
/// Communication necessary
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.None;
if (error==CommErr.None && (ihead.ConfigStruct.TestModeConfig != testModeConfig) && (ihead.ConfigStruct.MeterState != MeterState.Active))
{
/// Switch to Active mode in order to change TestModeConfig
error = CommErr.CmdActive;
byte[] cmd = new byte[1] { (byte)Command.SetActiveMode };
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.Command, 0, 1, cmd, cfg.CommTimeout))
{
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
/// Delay min. 250 ms
Thread.Sleep(Math.Max(250, cfg.DelayBetweenRetries));
}
if (error == CommErr.None && (ihead.ConfigStruct.TestModeConfig != testModeConfig))
{
/// Change the TestModeConfig if necessary
error = CommErr.Write;
byte[] tstMdCfg = new byte[1] { testModeConfig };
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.Configuration, 21, 1, tstMdCfg, cfg.CommTimeout))
{
ihead.ConfigStruct.Update(21, tstMdCfg);
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
/// Delay min. 250 ms
Thread.Sleep(Math.Max(250, cfg.DelayBetweenRetries));
}
if (error == CommErr.None)
{
/// Switch to test mode
error = CommErr.CmdTest;
byte[] cmd = new byte[1] { (byte)Command.SetTestMode };
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.Command, 0, 1, cmd, cfg.CommTimeout))
{
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
/// Delay min. 250 ms
Thread.Sleep(Math.Max(250, cfg.DelayBetweenRetries));
}
/// Now the meter should be in the Test mode ... verify
if (error == CommErr.None)
{
/// Verify the configuration
error = CommErr.Verify;
byte[] config = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == ReadRequestPort(threadId, ihead, MessageID.Configuration, 0, ConfigStruct.Length, out config, cfg.CommTimeout))
{
ihead.ConfigStruct = ConfigStruct.FromByteArray(config);
if ((ihead.ConfigStruct.MeterState == MeterState.Test) && (ihead.ConfigStruct.TestModeConfig == testModeConfig))
{
error = CommErr.None;
resultStr = ihead.ConfigStruct.ToString(1);
break;
}
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
/// <summary>
/// Set the watermeter to the active mode.
/// Read a part of configuration afterwards to verify the mode was set correctly.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr SetActiveMode(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.CmdActive;
/// Switch to active mode
byte[] cmd = new byte[1] { (byte)Command.SetActiveMode };
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.Command, 0, 1, cmd, cfg.CommTimeout))
{
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
#if VERIFY_ACTIVE_MODE
if (error == CommErr.None)
{
error = CommErr.Verify;
/// Read configuration
byte[] cfg_0_3 = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (ihead.ConfigStruct == null)
{
if (0 == ReadRequestPort(threadId, ihead, MessageID.Configuration, 0, 4, out cfg_0_3, cfg.CommTimeout))
{
ihead.ConfigStruct.Update(0, cfg_0_3);
if (ihead.ConfigStruct.MeterState == MeterState.Active)
{
error = CommErr.None;
resultStr = ihead.ConfigStruct.ToString(1);
break;
}
}
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
#else
if (error == CommErr.None)
{
if (ihead.ConfigStruct == null)
resultStr = "OK (Config not available)";
else
resultStr = ihead.ConfigStruct.ToString(1);
}
#endif
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
/// <summary>
/// Read a complete calibration structure from the watermeter
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr ReadCalibration(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed) return CommErr.CommFailed;
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Read;
int readRetVal = 0;
/// Read calibration
byte[] calib = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
readRetVal = ReadRequestPort(threadId, ihead, MessageID.Calibration, 0, CalibrationStruct.Length, out calib, cfg.CommTimeout);
if (readRetVal == 0)
{
ihead.CalibrationStruct = CalibrationStruct.FromByteArray(calib);
if (wm.OrigCalibFactor == 0)
{
wm.OrigCalibFactor = ihead.CalibrationStruct.Calibration;
wm.FWVersion = ihead.CalibrationStruct.FWVersionStr();
}
resultStr = ihead.CalibrationStruct.ToString();
error = ihead.VerifyIPerlType() ? CommErr.None : CommErr.WrongIPerlType;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
ClosePort(threadId, ihead); /// Close RFID port
return error + Math.Max(0, Math.Min(readRetVal, 4));
}
/// <summary>
/// Read a complete calibration structure from the watermeter
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr ReadCalibrationV4(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed) return CommErr.CommFailed;
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Read;
int readRetVal = 0;
/// Read calibration
byte[] calib = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
readRetVal = ReadRequestPort(threadId, ihead, MessageID.Calibration, 0, CalibrationStructV4.Length, out calib, cfg.CommTimeout);
if (readRetVal == 0)
{
ihead.CalibrationStructV4 = CalibrationStructV4.FromByteArray(calib);
if ((wm.OrigCalibFactor == 0) && (wm.OrigCalibFactorLNA == 0))
{
wm.OrigCalibFactor = ihead.CalibrationStructV4.Calibration;
wm.OrigCalibFactorLNA = ihead.CalibrationStructV4.CalibrationLNA;
wm.FWVersion = ihead.CalibrationStructV4.FWVersionStr();
}
resultStr = ihead.CalibrationStructV4.ToString();
error = ihead.VerifyIPerlType() ? CommErr.None : CommErr.WrongIPerlType;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
ClosePort(threadId, ihead); /// Close RFID port
return error + Math.Max(0, Math.Min(readRetVal, 4));
}
/// <summary>
/// Write the calculated calibration factor to the water meter.
/// Read a part of CalibrationStruct afterwards to verify factor was written correctly.
/// </summary>
/// <param name="threadId">Thread ID</param>
/// <param name="ihead">IperlHead object</param>
/// <param name="wm">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr WriteCalibrationFactor(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed || (ihead.CalibrationStruct == null)) return CommErr.CommFailed;
///
/// Parse calibration factor (1 argument) or calibration factor limits (2 arguments)
///
UInt16 newCalibFactor = 0;
if (multiTestParams[currentActivityStep].Activity.Length > WriteCalibrationFactorStr.Length)
{
UInt16 factorLimitLo;
UInt16 factorLimitHi;
UInt16 val;
string calibFactrorStr = multiTestParams[currentActivityStep].Activity.Substring(WriteCalibrationFactorStr.Length + 1);
string[] arguments = calibFactrorStr.Split(new char[] { ' ' });
if (arguments.Length >= 2 &&
UInt16.TryParse(arguments[0], out factorLimitLo) && factorLimitLo > 0 &&
UInt16.TryParse(arguments[1], out factorLimitHi) && factorLimitHi > 0)
{
///
/// Lower and upper limits for the calibration factor are specified as iPerlCommunication activity arguments
///
if (ihead.LastTestResult == null || !ihead.LastTestResult.TestDone) return CommErr.MissingTest;
newCalibFactor = ihead.CalculateNewCalibFactor(ihead.LastTestResult, ihead.CalibFactor, factorLimitLo, factorLimitHi);
}
else if (arguments.Length == 1 && UInt16.TryParse(arguments[0], out val) && val > 0)
{
///
/// Calibration factor value is specified as an iPerlCommunication activity argument
///
newCalibFactor = val; /// Update with specified value
}
else if (arguments.Length == 1 && wm.GetTestData(arguments[0]) != null)
{
///
/// Adjustment test name is specified as an iPerlCommunication activity argument
///
Results.Entities.TestData adjustTestData = wm.GetTestData(arguments[0]);
Results.Entities.MeterTestRslt adjustTestRslt;
if (adjustTestData == null)
{
return CommErr.MissingTest;
}
else if (adjustTestData.Repeats == 1)
{
/// Find a test result if Repeats == 1
adjustTestRslt = wm.GetMeterTestRslt(arguments[0]);
if (adjustTestRslt == null || !adjustTestRslt.TestDone) return CommErr.MissingTest;
}
else
{
/// Calculate a summarized test result if Repeats > 1
adjustTestRslt = new Results.Entities.MeterTestRslt();
for (int i = 1; i <= adjustTestData.Repeats; i++)
{
Results.Entities.MeterTestRslt oneMTR = wm.GetMeterTestRslt(Utils.TestTitle(adjustTestData, i));
if (oneMTR == null || !oneMTR.TestDone) return CommErr.MissingTest;
adjustTestRslt.VolumeMeter += oneMTR.VolumeMeter;
adjustTestRslt.VolumeRef += oneMTR.VolumeRef;
}
}
newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, ihead.FactorLimitLo, ihead.FactorLimitHi);
}
else
{
///
/// Otherwise the last test is supposed to be an adjustment test
///
if (ihead.LastTestResult == null || !ihead.LastTestResult.TestDone) return CommErr.MissingTest;
newCalibFactor = ihead.CalculateNewCalibFactor(ihead.LastTestResult, ihead.CalibFactor, ihead.FactorLimitLo, ihead.FactorLimitHi);
}
}
else
{
///
/// No iPerlCommunication activity arguments --> The last test is supposed to be an adjustment test
///
if (ihead.LastTestResult == null || !ihead.LastTestResult.TestDone) return CommErr.MissingTest;
newCalibFactor = ihead.CalculateNewCalibFactor(ihead.LastTestResult, ihead.CalibFactor, ihead.FactorLimitLo, ihead.FactorLimitHi);
}
if (newCalibFactor == 0) return CommErr.OutOfRange;
///
/// Start communication with iPerl
///
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error;
byte[] data = new byte[2] { (byte)(newCalibFactor & 0x00FF), (byte)((newCalibFactor >> 8) & 0x00FF) };
int writeAndVerifyRetries = 0;
do
{
///
/// Write the new calibration factor (up to cfg.MaxCommRetries tims)
///
error = CommErr.Write;
if (0 == WriteRequestPort(threadId, ihead, MessageID.Calibration, 2, 2, data, cfg.CommTimeout))
{
///
/// Read and verify the calibration factor
///
error = CommErr.ReadAfterWrite;
byte[] calib_2_3 = null;
if (0 == ReadRequestPort(threadId, ihead, MessageID.Calibration, 2, 2, out calib_2_3, cfg.CommTimeout))
{
error = CommErr.Verify;
if (calib_2_3 != null && calib_2_3.Length == 2 && data[0] == calib_2_3[0] && data[1] == calib_2_3[1])
{
error = CommErr.None;
ihead.CalibrationStruct.Update(data, 2);
wm.CalibFactor = newCalibFactor;
resultStr = ihead.CalibrationStruct.ToString();
break;
}
}
}
ihead.CalibrationStruct.Update(data, 2);
}
while (++writeAndVerifyRetries <= cfg.MaxCommRetries);
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
/// <summary>
/// Write the calculated calibration factor to the water meter.
/// Read a part of CalibrationStruct afterwards to verify factor was written correctly.
/// </summary>
/// <param name="threadId">Thread ID</param>
/// <param name="ihead">IperlHead object</param>
/// <param name="wm">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr WriteCalibrationV4Factors(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed || (ihead.CalibrationStructV4 == null)) return CommErr.CommFailed;
///
/// Parse calibration factor (1 argument) or calibration factor limits (2 arguments)
///
UInt16 newCalibFactor = 0;
UInt16 newCalibFactorLNA = 0;
if (multiTestParams[currentActivityStep].Activity.Length > WriteCalibrationV4FactorsStr.Length)
{
UInt16 factorLimitLo = 0;
UInt16 factorLimitHi = 0;
UInt16 lnaFactorLimitLo = 0;
UInt16 lnaFactorLimitHi = 0;
Results.Entities.TestData adjustTestData = null;
Results.Entities.TestData lnaAdjustTestData = null;
Results.Entities.MeterTestRslt adjustTestRslt = null;
Results.Entities.MeterTestRslt lnaAdjustTestRslt = null;
string calibFactrorStr = multiTestParams[currentActivityStep].Activity.Substring(WriteCalibrationV4FactorsStr.Length + 1);
string[] arguments = calibFactrorStr.Split(new char[] { ' ' });
if (arguments.Length == 6)
{
if (!wm.TryGetTestData(arguments[0], out adjustTestData) ||
!UInt16.TryParse(arguments[1], out factorLimitLo) || factorLimitLo <= 0 &&
!UInt16.TryParse(arguments[2], out factorLimitHi) || factorLimitHi <= 0 &&
!wm.TryGetTestData(arguments[3], out lnaAdjustTestData) ||
!UInt16.TryParse(arguments[4], out lnaFactorLimitLo) || lnaFactorLimitLo <= 0 &&
!UInt16.TryParse(arguments[5], out lnaFactorLimitHi) || lnaFactorLimitHi <= 0)
{
return CommErr.WrongArguments;
}
else
{
adjustTestRslt = GetAverageTestRslt(wm, adjustTestData);
lnaAdjustTestRslt = GetAverageTestRslt(wm, lnaAdjustTestData);
if ((adjustTestRslt == null) || (lnaAdjustTestRslt == null))
{
return CommErr.MissingTest;
}
newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, factorLimitLo, factorLimitHi);
newCalibFactorLNA = ihead.CalculateNewCalibFactor(lnaAdjustTestRslt, ihead.CalibFactorLNA, lnaFactorLimitLo, lnaFactorLimitHi);
}
}
else if (arguments.Length == 4)
{
if (!wm.TryGetTestData(arguments[0], out adjustTestData) ||
!wm.TryGetTestData(arguments[1], out lnaAdjustTestData) ||
!UInt16.TryParse(arguments[2], out lnaFactorLimitLo) || lnaFactorLimitLo <= 0 &&
!UInt16.TryParse(arguments[3], out lnaFactorLimitHi) || lnaFactorLimitHi <= 0)
{
return CommErr.WrongArguments;
}
else
{
factorLimitLo = ihead.FactorLimitLo;
factorLimitHi = ihead.FactorLimitHi;
adjustTestRslt = GetAverageTestRslt(wm, adjustTestData);
lnaAdjustTestRslt = GetAverageTestRslt(wm, lnaAdjustTestData);
if ((adjustTestRslt == null) || (lnaAdjustTestRslt == null))
{
return CommErr.MissingTest;
}
newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, factorLimitLo, factorLimitHi);
newCalibFactorLNA = ihead.CalculateNewCalibFactor(lnaAdjustTestRslt, ihead.CalibFactorLNA, lnaFactorLimitLo, lnaFactorLimitHi);
}
}
else if (arguments.Length == 2)
{
if (!wm.TryGetTestData(arguments[0], out adjustTestData) ||
!wm.TryGetTestData(arguments[1], out lnaAdjustTestData))
{
return CommErr.WrongArguments;
}
else
{
factorLimitLo = ihead.FactorLimitLo;
factorLimitHi = ihead.FactorLimitHi;
lnaFactorLimitLo = ihead.FactorLimitLo;
lnaFactorLimitHi = ihead.FactorLimitHi;
adjustTestRslt = GetAverageTestRslt(wm, adjustTestData);
lnaAdjustTestRslt = GetAverageTestRslt(wm, lnaAdjustTestData);
if ((adjustTestRslt == null) || (lnaAdjustTestRslt == null))
{
return CommErr.MissingTest;
}
newCalibFactor = ihead.CalculateNewCalibFactor(adjustTestRslt, ihead.CalibFactor, factorLimitLo, factorLimitHi);
newCalibFactorLNA = ihead.CalculateNewCalibFactor(lnaAdjustTestRslt, ihead.CalibFactorLNA, lnaFactorLimitLo, lnaFactorLimitHi);
}
}
else
{
return CommErr.WrongArguments;
}
}
else
{
return CommErr.WrongArguments;
}
if (newCalibFactor == 0 || newCalibFactorLNA == 0) return CommErr.OutOfRange;
///
/// Start communication with iPerl
///
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error;
byte[] data = new byte[2] { (byte)(newCalibFactor & 0x00FF), (byte)((newCalibFactor >> 8) & 0x00FF) };
byte[] dataLNA = new byte[2] { (byte)(newCalibFactorLNA & 0x00FF), (byte)((newCalibFactorLNA >> 8) & 0x00FF) };
int writeAndVerifyRetries = 0;
do
{
///
/// Write the new calibration factor (up to cfg.MaxCommRetries tims)
///
error = CommErr.Write;
if (0 == WriteRequestPort(threadId, ihead, MessageID.Calibration, 2, 2, data, cfg.CommTimeout) &&
0 == WriteRequestPort(threadId, ihead, MessageID.Calibration, 34, 2, dataLNA, cfg.CommTimeout))
{
///
/// Read and verify the calibration factor
///
error = CommErr.ReadAfterWrite;
byte[] calib_2_3 = null;
byte[] calib_34_35 = null;
if (0 == ReadRequestPort(threadId, ihead, MessageID.Calibration, 2, 2, out calib_2_3, cfg.CommTimeout) &&
0 == ReadRequestPort(threadId, ihead, MessageID.Calibration, 34, 2, out calib_34_35, cfg.CommTimeout))
{
error = CommErr.Verify;
if (calib_2_3 != null && calib_2_3.Length == 2 && data[0] == calib_2_3[0] && data[1] == calib_2_3[1] &&
calib_34_35 != null && calib_34_35.Length == 2 && dataLNA[0] == calib_34_35[0] && dataLNA[1] == calib_34_35[1])
{
error = CommErr.None;
ihead.CalibrationStructV4.Update(data, 2);
ihead.CalibrationStructV4.Update(dataLNA, 34);
wm.CalibFactor = newCalibFactor;
wm.CalibFactorLNA = newCalibFactorLNA;
resultStr = ihead.CalibrationStructV4.ToString();
break;
}
}
}
ihead.CalibrationStructV4.Update(data, 2);
ihead.CalibrationStructV4.Update(dataLNA, 34);
writeAndVerifyRetries++;
if ((writeAndVerifyRetries <= cfg.MaxCommRetries) && (cfg.DelayBetweenRetries > 0))
{
/// Delay between retries
Thread.Sleep(cfg.DelayBetweenRetries);
}
}
while (writeAndVerifyRetries <= cfg.MaxCommRetries);
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
/// <summary>
/// Get averaged meter test result using test name and repetitions from a given test data.
/// </summary>
/// <param name="wm">Water meter</param>
/// <param name="testData">TestData (name and repetitions)</param>
/// <returns>(1) selected MeterTestRslt or (2) average of repeated MTR-s or (3) null when at least one MTR is missing</returns>
static Results.Entities.MeterTestRslt GetAverageTestRslt(Results.Entities.WaterMeter wm, Results.Entities.TestData testData)
{
Results.Entities.MeterTestRslt avgTestRslt;
if (testData.Repeats > 1)
{
/// Calculate a summarized test result if Repeats > 1
avgTestRslt = new Results.Entities.MeterTestRslt();
for (int i = 1; i <= testData.Repeats; i++)
{
Results.Entities.MeterTestRslt oneMTR = wm.GetMeterTestRslt(Utils.TestTitle(testData, i));
if (oneMTR == null || !oneMTR.TestDone) return null;
avgTestRslt.VolumeMeter += oneMTR.VolumeMeter;
avgTestRslt.VolumeRef += oneMTR.VolumeRef;
}
}
else
{
avgTestRslt = wm.GetMeterTestRslt(Utils.TestTitle(testData, 1));
if (avgTestRslt == null || !avgTestRslt.TestDone) return null;
}
return avgTestRslt;
}
/// <summary>
/// Normalize calibration factor in case ti is close to value 8000.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr NormalizeCalibrationFactor(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed || (ihead.CalibrationStruct == null)) return CommErr.CommFailed;
if (ihead.FactorLimitLo <= ihead.CalibFactor && ihead.CalibFactor <= ihead.FactorLimitHi)
{
resultStr = "Calibratin factor is OK";
return CommErr.None; /// No need to update the calibration factor
}
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Write;
/// Determine the new calibration factor
UInt16 defaultCalibFactor;
switch (ihead.CalibrationStruct.MeterType)
{
case MeterType.DN15: defaultCalibFactor = 2710; break;
case MeterType.DN20: defaultCalibFactor = 3746; break;
case MeterType.DN25: defaultCalibFactor = 3300; break;
case MeterType.DN32: defaultCalibFactor = 2500; break;
case MeterType.DN40: defaultCalibFactor = 3080; break;
case MeterType.DN26:
case MeterType.CoaxManifold:
default:
defaultCalibFactor = 3040;
break;
}
byte[] data = new byte[2] { (byte)(defaultCalibFactor & 0x00FF), (byte)((defaultCalibFactor >> 8) & 0x00FF) };
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.Calibration, 2, 2, data, cfg.CommTimeout))
{
error = CommErr.None;
ihead.CalibrationStruct.Update(data, 2);
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
if (error == CommErr.None)
{
error = CommErr.Verify;
/// Read calibration
byte[] calib_2_3 = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == ReadRequestPort(threadId, ihead, MessageID.Calibration, 2, 2, out calib_2_3, cfg.CommTimeout))
{
error = CommErr.None;
ihead.CalibrationStruct.Update(calib_2_3, 2);
resultStr = ihead.CalibrationStruct.ToString();
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
/// <summary>
/// Normalize calibration factor in case ti is close to value 8000.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr NormalizeCalibrationV4Factors(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed || (ihead.CalibrationStructV4 == null)) return CommErr.CommFailed;
if (ihead.FactorLimitLo <= ihead.CalibFactor && ihead.CalibFactor <= ihead.FactorLimitHi)
{
resultStr = "Calibratin factor is OK";
return CommErr.None; /// No need to update the calibration factor
}
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Write;
/// Determine the new calibration factor
UInt16 defaultCalibFactor;
switch (ihead.CalibrationStructV4.MeterType)
{
case MeterType.DN15: defaultCalibFactor = 2710; break;
case MeterType.DN20: defaultCalibFactor = 3746; break;
case MeterType.DN25: defaultCalibFactor = 3300; break;
case MeterType.DN32: defaultCalibFactor = 2500; break;
case MeterType.DN40: defaultCalibFactor = 3080; break;
case MeterType.DN26:
case MeterType.CoaxManifold:
default:
defaultCalibFactor = 3040;
break;
}
byte[] data = new byte[2] { (byte)(defaultCalibFactor & 0x00FF), (byte)((defaultCalibFactor >> 8) & 0x00FF) };
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.Calibration, 2, 2, data, cfg.CommTimeout))
{
error = CommErr.None;
ihead.CalibrationStructV4.Update(data, 2);
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
if (error == CommErr.None)
{
error = CommErr.Verify;
/// Read calibration
byte[] calib_2_3 = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == ReadRequestPort(threadId, ihead, MessageID.Calibration, 2, 2, out calib_2_3, cfg.CommTimeout))
{
error = CommErr.None;
ihead.CalibrationStructV4.Update(calib_2_3, 2);
resultStr = ihead.CalibrationStructV4.ToString();
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
/// <summary>
/// Reset both Q2 correction factors in the memory to 0.
/// Read them back to verify factors were written correctly.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr ReadQ2Correction(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed) return CommErr.CommFailed;
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Read;
/// Write zero Q2 correction
byte[] rdData = null;
///
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == ReadRequestPort(threadId, ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddr, 2, out rdData, cfg.CommTimeout))
{
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
if ((error == CommErr.None) && (rdData != null) && (rdData.Length == 2))
{
resultStr = "Q2 corrections successfully read";
wm.Q2CorrLR = ihead.Q2CorrLR = (int)((SByte)rdData[0]);
wm.Q2CorrRL = ihead.Q2CorrRL = (int)((SByte)rdData[1]);
}
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
/// <summary>
/// Reset both Q2 correction factors in the memory to 0.
/// Read them back to verify factors were written correctly.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr ResetQ2Correction(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
return SetQ2Correction(threadId, ihead, wm, ref resultStr, 0, 0);
}
/// <summary>
/// Reset both Q2 correction factors in the memory to 0.
/// Read them back to verify factors were written correctly.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr SetQ2Correction(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr, int factorLR, int factorRL)
{
if (ihead.CommFailed) return CommErr.CommFailed;
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Write;
/// Write zero Q2 correction
byte[] wrData = new byte[2] { (byte)factorLR, (byte)factorRL };
///
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddr, wrData.Length, wrData, cfg.CommTimeout))
{
wm.Q2CorrRL = ihead.Q2CorrRL = factorRL;
wm.Q2CorrLR = ihead.Q2CorrLR = factorLR;
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
///
/// Verification disabled on 16.02.2016
///
#if VERIFY_Q2_CORR_RESET
/// Verify the correction factors
if (error == CommErr.None)
{
error = CommErr.Verify;
/// Read calibration
byte[] rdData = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if ((0 == ReadRequestPort(threadId, ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddr, 2, out rdData, cfg.CommTimeout)) &&
(rdData != null) && (rdData.Length == 2) && (rdData[0] == 0) && (rdData[1] == 0))
{
error = CommErr.None;
resultStr = string.Format("Q2 correction set to LR={0}, RL={1}", factorLR, factorRL);
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
#else
if (error == CommErr.None)
{
resultStr = string.Format("Q2 correction set to LR={0}, RL={1}", factorLR, factorRL);
}
#endif
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
static CommErr InitOrReadQ2Correction(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed) return CommErr.CommFailed;
if (wm.Pruefindex == 1)
{
if (TBF.BenchControl.Sequences.ProcessData.IsQ2PreCorrectionCalculated)
{
return SetQ2Correction(threadId, ihead, wm, ref resultStr, TBF.BenchControl.Sequences.ProcessData.CalculatedQ2PreCorrectionLR,
TBF.BenchControl.Sequences.ProcessData.CalculatedQ2PreCorrectionRL);
}
else
{
return SetQ2Correction(threadId, ihead, wm, ref resultStr, ihead.Q2PreCorrectionLR, ihead.Q2PreCorrectionRL);
}
}
else
{
return ReadQ2Correction(threadId, ihead, wm, ref resultStr);
}
}
/// <summary>
/// Reset 2Hz correction factor in the memory to 0.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr Reset2HzCorrection(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed) return CommErr.CommFailed;
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Write;
/// Write zero Q2 correction
byte[] wrData = new byte[1] { 0 };
///
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.MetrologyMemory, Hz2CorrFactorsAddr, wrData.Length, wrData, cfg.CommTimeout))
{
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
///
/// Verification disabled on 16.02.2016
///
#if false
/// Verify the correction factors
if (error == CommErr.None)
{
error = CommErr.Verify;
/// Read calibration
byte[] rdData = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if ((0 == ReadRequestPort(threadId, ihead, MessageID.MetrologyMemory, Hz2CorrFactorsAddr, 1, out rdData, cfg.CommTimeout)) &&
(rdData != null) && (rdData.Length == 2) && (rdData[0] == 0) && (rdData[1] == 0))
{
error = CommErr.None;
resultStr = "2Hz correction reset to 0";
ihead.Q2CorrectionFactor = 0;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
#else
if (error == CommErr.None)
{
resultStr = "2Hz correction reset to 0";
ihead.Hz2Correction = 0;
}
#endif
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
/// <summary>
/// Write the calculated Q2 correction factors to the memory.
/// Read them back to verify factors were written correctly.
///
/// Write Q2 correction
/// Write Q2 correction Alt
/// Write Q2 correction [Greece | R-L | L-R] testname
/// Update Q2 corrections
/// Conditional update of Q2 corrections
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr WriteQ2Correction(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, Test test, ref string resultStr,
Q2CorrType q2CorrType, string restOfLine)
{
if ((q2CorrType == Q2CorrType.ConditionalUpdate) && wm.PassedFromTests())
{
resultStr = string.Format("No Q2 correction update (iPerl is OK)");
return CommErr.None; /// No Q2 correction when doing conditional update and WM passed
}
string[] args = new string[0];
if (!string.IsNullOrEmpty(restOfLine))
{
args = restOfLine.Split(new char[] { ' ' });
}
Results.Entities.MeterTestRslt q2adjResult; /// The only test or the 1st test (the test in R-L direction)
Results.Entities.TestData q2adjTestData;
///
if (args.Length == 0)
{
/// In case of no test name argument, ihead.LastTestResult is used (if it exists)
if ((ihead.LastTestResult == null) || !ihead.LastTestResult.TestDone) return CommErr.MissingTest;
q2adjResult = ihead.LastTestResult;
q2adjTestData = q2adjResult.TestRslt.TestData;
}
else // if (args.Length >= 1)
{
/// Get test data from (the 1st) test name
q2adjTestData = wm.GetTestData(args[0]);
if (q2adjTestData == null) return CommErr.MissingTest;
if (q2adjTestData.Repeats == 1)
{
/// Find a test result if Repets == 1
q2adjResult = wm.GetMeterTestRslt(args[0]);
if (q2adjResult == null || !q2adjResult.TestDone) return CommErr.MissingTest;
}
else
{
/// Calculate a summarized test result if Repeats > 1
q2adjResult = new Results.Entities.MeterTestRslt();
for (int i = 1; i <= q2adjTestData.Repeats; i++)
{
Results.Entities.MeterTestRslt oneMTR = wm.GetMeterTestRslt(string.Format("{0} ({1}/{2})", args[0], i, q2adjTestData.Repeats));
if (oneMTR == null || !oneMTR.TestDone) return CommErr.MissingTest;
q2adjResult.VolumeMeter += oneMTR.VolumeMeter;
q2adjResult.VolumeRef += oneMTR.VolumeRef;
}
q2adjResult.Error = Config.Formulas.ErrorFromVolumes(q2adjResult.VolumeMeter, q2adjResult.VolumeRef);
}
}
Results.Entities.MeterTestRslt q2adjResult2 = null; /// 2nd test name for a test in L-R direction
Results.Entities.TestData q2adjTestData2 = null;
///
if (args.Length >= 2)
{
/// Get the 2nd test data from the 2nd test name
q2adjTestData2 = wm.GetTestData(args[1]);
if (q2adjTestData2 == null) return CommErr.MissingTest;
if (q2adjTestData2.Repeats == 1)
{
/// Find a test result if Repets == 1
q2adjResult2 = wm.GetMeterTestRslt(args[1]);
if (q2adjResult2 == null || !q2adjResult2.TestDone) return CommErr.MissingTest;
}
else
{
/// Calculate a summarized test result if Repeats > 1
q2adjResult2 = new Results.Entities.MeterTestRslt();
for (int i = 1; i <= q2adjTestData2.Repeats; i++)
{
Results.Entities.MeterTestRslt oneMTR = wm.GetMeterTestRslt(string.Format("{0} ({1}/{2})", args[1], i, q2adjTestData2.Repeats));
if (oneMTR == null || !oneMTR.TestDone) return CommErr.MissingTest;
q2adjResult2.VolumeMeter += oneMTR.VolumeMeter;
q2adjResult2.VolumeRef += oneMTR.VolumeRef;
}
q2adjResult2.Error = Config.Formulas.ErrorFromVolumes(q2adjResult2.VolumeMeter, q2adjResult2.VolumeRef);
}
}
if (q2adjResult == null)
{
return CommErr.MissingTest; /// This should never happen
}
if ((q2CorrType == Q2CorrType.Update || q2CorrType == Q2CorrType.ConditionalUpdate) && (q2adjResult2 == null))
{
return CommErr.MissingTest; /// This should never happen, 2 test names required as activity arguments
}
///
/// Calculate Q2 correction factor(s) from an error measured at Q2
///
double q2Correction = 0;
double q2Correction2 = 0; /// L-R direction in case of Q2CorrType.Update and Q2CorrType.ConditionalUpdate
///
if ((q2CorrType == Q2CorrType.Update) || (q2CorrType == Q2CorrType.ConditionalUpdate))
{
///
/// Update or ConditionalUpdate: 1. Calculate updates, not corrections, 2. Use error limits from this test
///
double errLimitLo = test.ErrLimLo + test.Uncertainty;
double errLimitHi = test.ErrLimHi - test.Uncertainty;
if (errLimitLo <= q2adjResult.Error && q2adjResult.Error <= errLimitHi &&
errLimitLo <= q2adjResult2.Error && q2adjResult2.Error <= errLimitHi)
{
/// Calculate updated Q2 correction factors
q2Correction = ihead.CalculateQ2CorrectionFactor(q2adjResult, ihead.CalibTargetQ2, q2adjTestData.Qfrom, wm.Q2CorrRL);
q2Correction2 = ihead.CalculateQ2CorrectionFactor(q2adjResult2, ihead.CalibTargetQ2, q2adjTestData2.Qfrom, wm.Q2CorrLR);
}
else
{
/// At least one of Q2 errors is out of range for Q2 correction
/// Q2 error is out of range for the Q2 correction
log.WarnFormat("OoR => no Q2 correction: Pos={0}, PCB#={1}, ***Q2_RL err={2}%***, ***Q2_LR err={3}%***, CalTarget={4}%, [Lo={5}%, Hi={6}%]",
ihead.Name,
ihead.SerialNr,
q2adjResult.Error.ToString("F2"),
q2adjResult2.Error.ToString("F2"),
ihead.CalibTargetQ2.ToString("F1"),
errLimitLo.ToString("F1"),
errLimitHi.ToString("F1"));
ihead.Q2CorrRL = wm.Q2CorrRL;
ihead.Q2CorrLR = wm.Q2CorrLR;
resultStr = string.Format("Q2 error is out of range => no Q2 correction");
return CommErr.Q2OutOfRange;
}
}
else
{
///
/// Regular Q2 corrections: 1. Use error limits from 'q2adjResult'
///
double errLimitLo = q2adjTestData.ErrLimLo + q2adjTestData.ErrLimMargin;
double errLimitHi = q2adjTestData.ErrLimHi - q2adjTestData.ErrLimMargin;
if ((errLimitLo <= q2adjResult.Error) && (q2adjResult.Error <= errLimitHi))
{
/// Calculate Q2 correction factor (assuming it was 0 when doing a test)
q2Correction = ihead.CalculateQ2CorrectionFactor(q2adjResult, ihead.CalibTargetQ2, q2adjTestData.Qfrom);
}
else
{
/// Q2 error is out of range for Q2 correction
log.WarnFormat("OoR => no Q2 correction: Pos={0}, PCB#={1}, ***Q2adj err={2}%***, CalTarget={3}%, [Lo={4}%, Hi={5}%]",
ihead.Name,
ihead.SerialNr,
q2adjResult.Error.ToString("F2"),
ihead.CalibTargetQ2.ToString("F1"),
errLimitLo.ToString("F1"),
errLimitHi.ToString("F1"));
resultStr = string.Format("Q2 error is out of range => no Q2 correction");
return CommErr.Q2OutOfRange;
}
}
Byte q2CorrRL = 0;
Byte q2CorrLR = 0;
///
if (q2CorrType == Q2CorrType.Standard)
{
///
/// Standard process
///
if (Math.Abs(q2adjResult.Error - ihead.CalibTargetQ2) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
q2CorrRL = (byte)((int)Math.Round(1.1 * q2Correction) & 0x000000FF);
q2CorrLR = (byte)((int)Math.Round(0.5 * q2Correction) & 0x000000FF);
}
else if (q2CorrType == Q2CorrType.Dewa)
{
///
/// Process for DEWA
///
if (Math.Abs(q2adjResult.Error - ihead.CalibTargetQ2) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
/// Use the same correction factor in both directions
q2CorrRL = (byte)((int)Math.Round(1.1 * q2Correction) & 0x000000FF);
q2CorrLR = (byte)((int)Math.Round(1.1 * q2Correction) & 0x000000FF);
}
else if (q2CorrType == Q2CorrType.Greece)
{
///
/// Process for Greece
///
if (Math.Abs(q2adjResult.Error - ihead.CalibTargetQ2) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
q2CorrRL = (byte)((int)Math.Round(2.2 * q2Correction) & 0x000000FF);
q2CorrLR = (byte)((int)Math.Round(1.1 * q2Correction) & 0x000000FF);
}
else if (q2CorrType == Q2CorrType.RL) /// SUEZ
{
if (Math.Abs(q2adjResult.Error - ihead.CalibTargetQ2) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
q2CorrRL = (byte)((int)Math.Round(q2Correction) & 0x000000FF);
}
else if (q2CorrType == Q2CorrType.LR) /// SUEZ
{
if (Math.Abs(q2adjResult.Error - ihead.CalibTargetQ2) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
q2CorrLR = (byte)((int)Math.Round(q2Correction) & 0x000000FF);
}
else if ((q2CorrType == Q2CorrType.Update) || (q2CorrType == Q2CorrType.ConditionalUpdate))
{
q2CorrRL = (byte)((int)Math.Round(q2Correction) & 0x000000FF);
q2CorrLR = (byte)((int)Math.Round(q2Correction2) & 0x000000FF);
}
///
/// Write calculated Q2 correction factors into the water meter
///
if (ihead.CommFailed) return CommErr.CommFailed;
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Write;
if (q2CorrType == Q2CorrType.RL)
{
///
/// Write R-L Q2 correction factor only
///
byte[] wrData = new byte[1] { q2CorrRL };
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddrRL, wrData.Length, wrData, cfg.CommTimeout))
{
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
else if (q2CorrType == Q2CorrType.LR)
{
///
/// Write L-R Q2 correction factor only
///
byte[] wrData = new byte[1] { q2CorrLR };
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddrLR, wrData.Length, wrData, cfg.CommTimeout))
{
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
else
{
///
/// Write both Q2 correction factors
///
byte[] wrData = new byte[2] { q2CorrLR, q2CorrRL };
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddr, wrData.Length, wrData, cfg.CommTimeout))
{
error = CommErr.None;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
///
/// Verification disabled on 16.02.2016
///
#if false
if (error == CommErr.None)
{
error = CommErr.Verify;
/// Read calibration
byte[] rdData = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if ((0 == ReadRequestPort(threadId, ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddr, 2, out rdData, cfg.CommTimeout)) &&
(rdData != null) && (rdData.Length == 2) && (rdData[0] == q2CorrRFlow) && (rdData[1] == q2CorrLFlow))
{
error = CommErr.None;
resultStr = string.Format("Q2 factors: R-flow={0}, L-flow={1}", (SByte)q2CorrRFlow, (SByte)q2CorrLFlow);
rfidDataLogger.Warn(ihead.Name + ": " + resultStr);
wm.Q2ErrWOCorrection = ihead.Q2ErrorWOCorrection;
if (q2CorrType != Q2CorrType.LR) wm.Q2CorrRFlow = ihead.Q2CorrRFlow = (int)(sbyte)q2CorrRFlow;
if (q2CorrType != Q2CorrType.RL) wm.Q2CorrLFlow = ihead.Q2CorrLFlow = (int)(sbyte)q2CorrLFlow;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
#else
///
/// Update WaterMeter entity and IperlHead
///
if (error == CommErr.None)
{
if (q2CorrType == Q2CorrType.RL)
{
resultStr = string.Format("Q2 correction: RL={0}", (SByte)q2CorrRL);
}
else if (q2CorrType == Q2CorrType.LR)
{
resultStr = string.Format("Q2 correction: LR={0}", (SByte)q2CorrLR);
}
else
{
resultStr = string.Format("Q2 correction: RL={0}, LR={1}", (SByte)q2CorrRL, (SByte)q2CorrLR);
}
rfidDataLogger.WarnFormat("{0}: {1}", ihead.Name, resultStr);
if ((q2CorrType != Q2CorrType.Update) && (q2CorrType != Q2CorrType.ConditionalUpdate))
{
wm.Q2ErrWOCorrection = ihead.Q2ErrWOCorrection = q2adjResult.Error;
}
if (q2CorrType != Q2CorrType.LR) wm.Q2CorrRL = ihead.Q2CorrRL = (int)(sbyte)q2CorrRL;
if (q2CorrType != Q2CorrType.RL) wm.Q2CorrLR = ihead.Q2CorrLR = (int)(sbyte)q2CorrLR;
}
#endif
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
/// <summary>
/// Write the calculated 2Hz correction factor to the memory.
/// </summary>
/// <param name="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
static CommErr Write2HzCorrection(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed) return CommErr.CommFailed;
/// Calculate the correction
ihead.Hz2CorrectionDone = false;
int hz2CorrectionFactor;
bool wmOK = ihead.Calculate2HzCorrectionFactor(ihead.LastTestResult2, ihead.LastTestResult, out ihead.Diff2Hz8Hz, out hz2CorrectionFactor);
if (hz2CorrectionFactor == 0)
{
resultStr = string.Format("2Hz correction = 0 (writing bypassed)");
return CommErr.None;
}
if (OpenPort(threadId, ihead) != 0) return CommErr.OpenPort; /// Open RFID port
CommErr error = CommErr.Write;
Byte hz2CorrectionByte = (byte)(hz2CorrectionFactor & 0x000000FF);
byte[] wrData = new byte[1] { hz2CorrectionByte };
///
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if (0 == WriteRequestPort(threadId, ihead, MessageID.MetrologyMemory, Hz2CorrFactorsAddr, wrData.Length, wrData, cfg.CommTimeout))
{
error = CommErr.None;
wm.Hz2Correction = ihead.Hz2Correction = hz2CorrectionFactor;
wm.Hz2CorrectionDone = ihead.Hz2CorrectionDone = true;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
///
/// Verification disabled on 16.02.2016
///
#if false
if (error == CommErr.None)
{
error = CommErr.Verify;
/// Read calibration
byte[] rdData = null;
for (int j = 0; j < cfg.MaxCommRetries; j++)
{
if ((0 == ReadRequestPort(wm, MessageID.MetrologyMemory, Hz2CorrFactorsAddr, 1, out rdData, cfg.CommTimeout)) &&
(rdData != null) && (rdData.Length == 2) && (rdData[0] == hz2CorrectionByte))
{
error = CommErr.None;
resultStr = string.Format("2Hz factor = {0}", (SByte)hz2CorrectionByte);
rfidDataLogger.Warn(ihead.Name + ": " + resultStr);
wm.Hz2Correction = ihead.Hz2CorrectionFactor = hz2CorrectionFactor;
wm.Diff2Hz8Hz = ihead.Diff2Hz8Hz;
wm.Hz2CorrectionDone = ihead.Hz2CorrectionDone;
break;
}
/// Delay between retries
if (cfg.DelayBetweenRetries > 0) Thread.Sleep(cfg.DelayBetweenRetries);
}
}
#else
if (error == CommErr.None)
{
resultStr = string.Format("2Hz correction = {0}", (SByte)hz2CorrectionByte);
rfidDataLogger.Warn(ihead.Name + ": " + resultStr);
wm.Diff2Hz8Hz = ihead.Diff2Hz8Hz;
wm.Hz2CorrectionDone = ihead.Hz2CorrectionDone = true;
wm.Hz2Correction = ihead.Hz2Correction = hz2CorrectionFactor;
}
#endif
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
#endif /// IPERL
#endregion
/// <summary>
/// Called when communication with one watermeter is completed
/// </summary>
public static void OnCommCompleted(object sender, CommCompletedEventArgs data)
{
if (CommCompletedHandler == null) return;
try { CommCompletedHandler(sender, data); }
catch (Exception e) { log.Error("CommCompletedHandler(...) failed", e); }
}
public static event EventHandler<CommCompletedEventArgs> CommCompletedHandler;
void DoOnCommCompleted(object sender, CommCompletedEventArgs data)
{
try
{
///
/// Update the text message
///
if (data.WMNr0 >= 0) messages[data.WMNr0].Text = data.CommMessage;
///
/// Update head active/inactive switch
///
if (data.WMNr0 >= 0 && data.CommErr == CommErr.HeadDisabledByUser)
{
/// iPerl head was disabled by the user
ckbState[data.WMNr0] = false;
checkBoxes[data.WMNr0].Checked = false;
checkBoxes[data.WMNr0].Enabled = false;
if (data.Ihead != null) data.Ihead.Disabled = true;
if (data.Wm != null) data.Wm.Disabled = true;
}
else if (data.WMNr0 >= 0 && data.CommErr == CommErr.None)
{
/// One RFID communication successful => iPerl cannot be disabled by the user anymore
ckbState[data.WMNr0] = true;
checkBoxes[data.WMNr0].Checked = true;
checkBoxes[data.WMNr0].Enabled = false;
}
///
/// Update opto-communication indication
///
for (int i = 0; i < iperlHeads.Count; i++)
{
if (iperlHeads[i] == null || iperlHeads[i].Disabled)
{
counters[i].BackColor = DisabledColor;
}
else
{
switch (iperlHeads[i].CheckFlowDirection())
{
case OptoHeadState.OptoAndDirOK:
counters[i].BackColor = OptoAndDirOKColor;
break;
case OptoHeadState.DirNok:
counters[i].BackColor = DirNokColor;
break;
default:
case OptoHeadState.OptoNok:
counters[i].BackColor = OptoNokColor;
break;
}
}
}
#if !TURA_SPECIAL
///
/// Branch
///
lock (this)
{
completedCommCount++;
if (cfg.UseMuxBoards && completedCommCount < muxBrdOrGroup14Nrs.Count) return;
if (!cfg.UseMuxBoards && completedCommCount < 4) return;
completedCommCount = 0;
}
#endif
if (currentGroup < lastGroup)
{
/// Go to the next step / next group
if (quido != null)
{
quido.SetOutputs((ushort)(16 - currentGroup - 1));
Thread.Sleep(2000);
}
currentGroup++;
}
else if (currentActivityStep + 1 < multiTestParams.Count)
{
currentGroup = 0;
currentActivityStep++;
activityLabel.Text = multiTestParams[currentActivityStep].Activity;
if (quido != null)
{
quido.SetOutputs((ushort)(16 - currentGroup - 1));
Thread.Sleep(2000);
}
currentGroup++;
}
else
{
/// Wait until all threads are finished
workerThreads[data.ThreadId].Join(2000);
NormalClose();
}
}
catch (Exception e)
{
log.ErrorFormat("DoOnCommCompleted({0}) failed: {1}", data, e.Message);
log.FatalFormat("StackTrace : {0}{1}", Environment.NewLine, e.StackTrace);
}
}
/// <summary>
/// Called when communication with all watermeters is completed
/// </summary>
public static void OnAllCompleted(object sender, AllCompletedEventArgs data)
{
if (AllCompletedHandler == null) return;
try { AllCompletedHandler(sender, data); }
catch (Exception e) { log.Error("AllCompletedHandler(...) failed", e); }
}
public static event EventHandler<AllCompletedEventArgs> AllCompletedHandler;
void DoOnAllCompleted(object sender, AllCompletedEventArgs data)
{
Text = data.CommMessage;
}
/// <summary>
/// Update test result representing RFID communication success/failure
/// </summary>
/// <param name="test"></param>
void UpdateRfidCommResult(IList<Config.Entities.Test> tests)
{
DateTime endTime = DateTime.Now;
int testTime = StateMachine.Time - startTimeSec;
if (!tests.Contains(StateMachine.Tests[0]))
{
tests.Insert(0, StateMachine.Tests[0]); /// Add RFID test as the 1st item
}
foreach (var test in tests)
{
Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(test.Name, test.Part);
if (tstRslt != null)
{
Results.Utils.GetCounterStates(tstRslt, Program.LocalSettings.Counters);
/// Auxiliary results ... not required
/// Main results
tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName;
tstRslt.StartTime = tstRslt.Batch.StartTime;
tstRslt.EndTime = endTime;
tstRslt.FlowSetTime = 0;
tstRslt.Buoyancy = Formulas.Buoyancy();
tstRslt.TestTime += testTime; /// [s] total communication time of all tests
for (int i = 0; i < iperlHeads.Count; i++)
{
Results.Entities.MeterTestRslt meterRslt =
ProcessData.BatchRslts.GetMeterTestRslt(test.Name, waterMeterPositions0[i], Config.Entities.CompoundMeterId.Single);
if (meterRslt != null && iperlHeads[i] != null)
{
#if ORACLE_DB
meterRslt.WaterMeter.WaterMeterData.WMTypeId = iperlHeads[i].WMType_ID;
#endif
meterRslt.WaterMeter.SerialNr = iperlHeads[i].SerialNr;
meterRslt.Passed = (!iperlHeads[i].CommFailed && !iperlHeads[i].Disabled);
meterRslt.TestDone = true;
}
}
}
}
UiBridge.Bridge.OnTestCompleted(this, new UiBridge.TestCompletedEventArgs(string.Empty, null));
}
#region Check boxes edit mode support
private void checkBoxImage1_Click(object sender, EventArgs e) { ckbState[ckbIndex[0]] = checkBoxImage1.Checked; }
private void checkBoxImage2_Click(object sender, EventArgs e) { ckbState[ckbIndex[1]] = checkBoxImage2.Checked; }
private void checkBoxImage3_Click(object sender, EventArgs e) { ckbState[ckbIndex[2]] = checkBoxImage3.Checked; }
private void checkBoxImage4_Click(object sender, EventArgs e) { ckbState[ckbIndex[3]] = checkBoxImage4.Checked; }
private void checkBoxImage5_Click(object sender, EventArgs e) { ckbState[ckbIndex[4]] = checkBoxImage5.Checked; }
private void checkBoxImage6_Click(object sender, EventArgs e) { ckbState[ckbIndex[5]] = checkBoxImage6.Checked; }
private void checkBoxImage7_Click(object sender, EventArgs e) { ckbState[ckbIndex[6]] = checkBoxImage7.Checked; }
private void checkBoxImage8_Click(object sender, EventArgs e) { ckbState[ckbIndex[7]] = checkBoxImage8.Checked; }
private void checkBoxImage9_Click(object sender, EventArgs e) { ckbState[ckbIndex[8]] = checkBoxImage9.Checked; }
private void checkBoxImage10_Click(object sender, EventArgs e) { ckbState[ckbIndex[9]] = checkBoxImage10.Checked; }
private void checkBoxImage11_Click(object sender, EventArgs e) { ckbState[ckbIndex[10]] = checkBoxImage11.Checked; }
private void checkBoxImage12_Click(object sender, EventArgs e) { ckbState[ckbIndex[11]] = checkBoxImage12.Checked; }
private void checkBoxImage13_Click(object sender, EventArgs e) { ckbState[ckbIndex[12]] = checkBoxImage13.Checked; }
private void checkBoxImage14_Click(object sender, EventArgs e) { ckbState[ckbIndex[13]] = checkBoxImage14.Checked; }
private void checkBoxImage15_Click(object sender, EventArgs e) { ckbState[ckbIndex[14]] = checkBoxImage15.Checked; }
private void checkBoxImage16_Click(object sender, EventArgs e) { ckbState[ckbIndex[15]] = checkBoxImage16.Checked; }
private void checkBoxImage17_Click(object sender, EventArgs e) { ckbState[ckbIndex[16]] = checkBoxImage17.Checked; }
private void checkBoxImage18_Click(object sender, EventArgs e) { ckbState[ckbIndex[17]] = checkBoxImage18.Checked; }
private void checkBoxImage19_Click(object sender, EventArgs e) { ckbState[ckbIndex[18]] = checkBoxImage19.Checked; }
private void checkBoxImage20_Click(object sender, EventArgs e) { ckbState[ckbIndex[19]] = checkBoxImage20.Checked; }
private void checkBoxImage21_Click(object sender, EventArgs e) { ckbState[ckbIndex[20]] = checkBoxImage21.Checked; }
private void checkBoxImage22_Click(object sender, EventArgs e) { ckbState[ckbIndex[21]] = checkBoxImage22.Checked; }
private void checkBoxImage23_Click(object sender, EventArgs e) { ckbState[ckbIndex[22]] = checkBoxImage23.Checked; }
private void checkBoxImage24_Click(object sender, EventArgs e) { ckbState[ckbIndex[23]] = checkBoxImage24.Checked; }
private void checkBoxImage25_Click(object sender, EventArgs e) { ckbState[ckbIndex[24]] = checkBoxImage25.Checked; }
private void checkBoxImage26_Click(object sender, EventArgs e) { ckbState[ckbIndex[25]] = checkBoxImage26.Checked; }
private void checkBoxImage27_Click(object sender, EventArgs e) { ckbState[ckbIndex[26]] = checkBoxImage27.Checked; }
private void checkBoxImage28_Click(object sender, EventArgs e) { ckbState[ckbIndex[27]] = checkBoxImage28.Checked; }
private void checkBoxImage29_Click(object sender, EventArgs e) { ckbState[ckbIndex[28]] = checkBoxImage29.Checked; }
private void checkBoxImage30_Click(object sender, EventArgs e) { ckbState[ckbIndex[29]] = checkBoxImage30.Checked; }
private void checkBoxImage31_Click(object sender, EventArgs e) { ckbState[ckbIndex[30]] = checkBoxImage31.Checked; }
private void checkBoxImage32_Click(object sender, EventArgs e) { ckbState[ckbIndex[31]] = checkBoxImage32.Checked; }
private void checkBoxImage33_Click(object sender, EventArgs e) { ckbState[ckbIndex[32]] = checkBoxImage33.Checked; }
private void checkBoxImage34_Click(object sender, EventArgs e) { ckbState[ckbIndex[33]] = checkBoxImage34.Checked; }
private void checkBoxImage35_Click(object sender, EventArgs e) { ckbState[ckbIndex[34]] = checkBoxImage35.Checked; }
private void checkBoxImage36_Click(object sender, EventArgs e) { ckbState[ckbIndex[35]] = checkBoxImage36.Checked; }
private void checkBoxImage37_Click(object sender, EventArgs e) { ckbState[ckbIndex[36]] = checkBoxImage37.Checked; }
private void checkBoxImage38_Click(object sender, EventArgs e) { ckbState[ckbIndex[37]] = checkBoxImage38.Checked; }
private void checkBoxImage39_Click(object sender, EventArgs e) { ckbState[ckbIndex[38]] = checkBoxImage39.Checked; }
private void checkBoxImage40_Click(object sender, EventArgs e) { ckbState[ckbIndex[39]] = checkBoxImage40.Checked; }
private void checkBoxImage41_Click(object sender, EventArgs e) { ckbState[ckbIndex[40]] = checkBoxImage41.Checked; }
private void checkBoxImage42_Click(object sender, EventArgs e) { ckbState[ckbIndex[41]] = checkBoxImage42.Checked; }
private void checkBoxImage43_Click(object sender, EventArgs e) { ckbState[ckbIndex[42]] = checkBoxImage43.Checked; }
private void checkBoxImage44_Click(object sender, EventArgs e) { ckbState[ckbIndex[43]] = checkBoxImage44.Checked; }
private void checkBoxImage45_Click(object sender, EventArgs e) { ckbState[ckbIndex[44]] = checkBoxImage45.Checked; }
private void checkBoxImage46_Click(object sender, EventArgs e) { ckbState[ckbIndex[45]] = checkBoxImage46.Checked; }
private void checkBoxImage47_Click(object sender, EventArgs e) { ckbState[ckbIndex[46]] = checkBoxImage47.Checked; }
private void checkBoxImage48_Click(object sender, EventArgs e) { ckbState[ckbIndex[47]] = checkBoxImage48.Checked; }
private long GetCheckBoxStates()
{
long result = 0;
for (int i = 0; i < 48; i++)
{
if (ckbState[ckbIndex[i]]) result += (1L << i);
}
return result;
}
private void SetCheckBoxStates(long state)
{
CheckBoxImage[] chkBoxes = new CheckBoxImage[48]
{
checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5,
checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10,
checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15,
checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20,
checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25,
checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30,
checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35,
checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40,
checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45,
checkBoxImage46, checkBoxImage47, checkBoxImage48,
};
for (int i = 0; i < 48; i++)
{
chkBoxes[i].Checked = ckbState[ckbIndex[i]] = ((state & (1L << i)) != 0);
}
}
private void saveButton_Click(object sender, EventArgs e)
{
Program.LocalSettings.iPerlCommunicationsFormCheckboxes = GetCheckBoxStates();
DialogResult = DialogResult.OK;
Close();
}
#endregion
private void iPerlCommunicationForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (!forcedClose && !formCompleted && !checkBoxesEditMode)
{
e.Cancel = true;
}
}
}
}