iPerl CalibrationStructV4 related stuff added, ver. 2.18.1004

This commit is contained in:
Milan Hanajik 2018-09-20 09:05:32 +02:00
parent 07b51f12a2
commit 92609b9ead
9 changed files with 705 additions and 76 deletions

View File

@ -58,9 +58,11 @@ namespace Results.Entities
#if IPERL
public virtual int SerialNrEx { get; set; } /// Aux s/n for compound meters, Serial number for iPerl water meter
public virtual double OrigCalibFactor { get; set; } /// iPerl calibration factor used during the test
public virtual double CalibFactor { get; set; } /// iPerl calibration factor used during the test
public virtual double Q2ErrWOCorrection { get; set; }
public virtual double OrigCalibFactor { get; set; } /// Original iPerl calibration factor used during the test
public virtual double CalibFactor { get; set; } /// iPerl calibration factor used during the test
public virtual double OrigCalibFactorLNA { get; set; } /// Original iPerl LNA calibration factor used during the test
public virtual double CalibFactorLNA { get; set; } /// iPerl LNA calibration factor used during the test
public virtual double Q2ErrWOCorrection { get; set; }
public virtual bool Q2CorrectionDone { get; set; } /// true = iPerl Q2 correction was done
public virtual double Q2Correction { get; set; } /// !!! obsolete
public virtual int Q2CorrRFlow { get; set; } /// iPerl Q2 correction for the R-flow written to iPerl
@ -264,6 +266,21 @@ namespace Results.Entities
return null;
}
public virtual bool TryGetTestRslt(string testName, out TestRslt testRslt)
{
MeterTestRslt mtr = GetMeterTestRslt(testName);
if (mtr != null)
{
testRslt = mtr.TestRslt;
return true;
}
else
{
testRslt = null;
return false;
}
}
public virtual TestData GetTestData(string testName)
{
foreach (var mtr in MeterTestRslts)
@ -276,6 +293,21 @@ namespace Results.Entities
return null;
}
public virtual bool TryGetTestData(string testName, out TestData testData)
{
foreach (var mtr in MeterTestRslts)
{
if (mtr.TestRslt.TestData.Name == testName)
{
testData = mtr.TestRslt.TestData;
return true;
}
}
testData = null;
return false;
}
/// <summary>

View File

@ -31,7 +31,13 @@ namespace Results.Mappings
Map(x => x.SerialNrEx);
Map(x => x.OrigCalibFactor);
Map(x => x.CalibFactor);
Map(x => x.Q2ErrWOCorrection);
#endif
#if IPERL2
Map(x => x.OrigCalibFactorLNA);
Map(x => x.CalibFactorLNA);
#endif
#if IPERL
Map(x => x.Q2ErrWOCorrection);
Map(x => x.Q2CorrectionDone);
Map(x => x.Q2Correction);
Map(x => x.Q2CorrRFlow);

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2015-2017 Sensus Metering Systems
/// Copyright (c) 2015-2018 Sensus Slovensko a.s.
///
//#define VERIFY_ACTIVE_MODE
//#define VERIFY_Q2_CORR_RESET
@ -41,6 +41,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
MissingTest, /// F = 15
RFPowerRecordMissing, /// 10H = 16
HeadDisabledByUser, /// 11H = 17
WrongArguments, /// 12H = 18
}
@ -171,8 +172,12 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
rfidDataLogger.InfoFormat("{0}: ReadRequestPort({1},...) returned {2} {3}", name, messageID, retv, (retv != 0) ? "!" : ConfigStruct.FromByteArray(buffer).ToString());
else if ((messageID == MessageID.Calibration) && (offset == 0) && (lenght == 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) && (lenght == 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) && (lenght == 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) && (lenght == 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
rfidDataLogger.InfoFormat("{0}: ReadRequestPort({1}, {2}, {3}, ...) returned {4} {5}", name, messageID, offset, lenght, retv, (retv != 0) ? "!" : "");
@ -231,20 +236,23 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
#endregion DLL_Interface
const string ReadConfigurationStr = "Read configuration"; /// Example: "Read configuration" or "Read configuration if enabled"
const string SetTestModeStr = "Set Test mode"; /// Example: "Set Test mode" or "Set Test mode A0" (hexadecimal number is the required 'testModeConfig'
const string SetActiveModeStr = "Set Active mode";
const string ReadCalibrationStr = "Read calibration";
const string WriteCalibrationFactorStr = "Write calibration factor";
const string NormalizeCalibrationFactorStr = "Normalize calibration factor";
const string ResetQ2CorrectionStr = "Reset Q2 correction";
const string WriteQ2CorrectionStr = "Write Q2 correction";
const string WriteQ2CorrectionAltStr = "Write Q2 correction Alt";
const string WriteQ2CorrectionGreeceStr = "Write Q2 correction Greece";
const string WriteQ2CorrectionRLStr = "Write Q2 correction R-L";
const string WriteQ2CorrectionLRStr = "Write Q2 correction L-R";
const string Reset2HzCorrectionStr = "Reset 2Hz correction";
const string Write2HzCorrectionStr = "Write 2Hz correction";
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 ResetQ2CorrectionStr = "Reset Q2 correction";
public const string WriteQ2CorrectionStr = "Write Q2 correction";
public const string WriteQ2CorrectionAltStr = "Write Q2 correction Alt";
public const string WriteQ2CorrectionGreeceStr = "Write Q2 correction Greece";
public const string WriteQ2CorrectionRLStr = "Write Q2 correction R-L";
public const string WriteQ2CorrectionLRStr = "Write Q2 correction L-R";
public const string Reset2HzCorrectionStr = "Reset 2Hz correction";
public const string Write2HzCorrectionStr = "Write 2Hz correction";
readonly bool checkBoxesEditMode;
@ -732,21 +740,24 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
///
/// RFID communication activity call
///
if (ihead.Disabled || !ckbState[wmNr0]) error = CommErr.HeadDisabledByUser;
else if (activity.ToLower().Contains(ReadConfigurationStr.ToLower())) error = ReadConfiguration(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Contains(SetTestModeStr.ToLower())) error = SetTestMode(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(SetActiveModeStr.ToLower())) error = SetActiveMode(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(ReadCalibrationStr.ToLower())) error = ReadCalibration(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Contains(WriteCalibrationFactorStr.ToLower())) error = WriteCalibrationFactor(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(NormalizeCalibrationFactorStr.ToLower())) error = NormalizeCalibrationFactor(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(ResetQ2CorrectionStr.ToLower())) error = ResetQ2Correction(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(WriteQ2CorrectionStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.Standard, null, false);
else if (activity.ToLower().Equals(WriteQ2CorrectionAltStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.Dewa, null, false);
else if (activity.ToLower().Contains(WriteQ2CorrectionGreeceStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.Greece, activity.Substring(WriteQ2CorrectionGreeceStr.Length).Trim(), true);
else if (activity.ToLower().Contains(WriteQ2CorrectionRLStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.RL, activity.Substring(WriteQ2CorrectionRLStr.Length).Trim(), true);
else if (activity.ToLower().Contains(WriteQ2CorrectionLRStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.LR, activity.Substring(WriteQ2CorrectionLRStr.Length).Trim(), true);
else if (activity.ToLower().Equals(Reset2HzCorrectionStr.ToLower())) error = Reset2HzCorrection(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(Write2HzCorrectionStr.ToLower())) error = Write2HzCorrection(threadID, ihead, wm, ref resultStr);
if (ihead.Disabled || !ckbState[wmNr0]) error = CommErr.HeadDisabledByUser;
else if (activity.ToLower().Contains(ReadConfigurationStr.ToLower())) error = ReadConfiguration(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Contains(SetTestModeStr.ToLower())) error = SetTestMode(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(SetActiveModeStr.ToLower())) error = SetActiveMode(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(ReadCalibrationStr.ToLower())) error = ReadCalibration(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(ReadCalibrationV4Str.ToLower())) error = ReadCalibrationV4(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Contains(WriteCalibrationFactorStr.ToLower())) error = WriteCalibrationFactor(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Contains(WriteCalibrationV4FactorsStr.ToLower())) error = WriteCalibrationV4Factors(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(NormalizeCalibrationFactorStr.ToLower())) error = NormalizeCalibrationFactor(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(NormalizeCalibrationV4FactorsStr.ToLower())) error = NormalizeCalibrationV4Factors(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(ResetQ2CorrectionStr.ToLower())) error = ResetQ2Correction(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(WriteQ2CorrectionStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.Standard, null, false);
else if (activity.ToLower().Equals(WriteQ2CorrectionAltStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.Dewa, null, false);
else if (activity.ToLower().Contains(WriteQ2CorrectionGreeceStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.Greece, activity.Substring(WriteQ2CorrectionGreeceStr.Length).Trim(), true);
else if (activity.ToLower().Contains(WriteQ2CorrectionRLStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.RL, activity.Substring(WriteQ2CorrectionRLStr.Length).Trim(), true);
else if (activity.ToLower().Contains(WriteQ2CorrectionLRStr.ToLower())) error = WriteQ2Correction(threadID, ihead, wm, ref resultStr, Q2CorrType.LR, activity.Substring(WriteQ2CorrectionLRStr.Length).Trim(), true);
else if (activity.ToLower().Equals(Reset2HzCorrectionStr.ToLower())) error = Reset2HzCorrection(threadID, ihead, wm, ref resultStr);
else if (activity.ToLower().Equals(Write2HzCorrectionStr.ToLower())) error = Write2HzCorrection(threadID, ihead, wm, ref resultStr);
else
{
error = CommErr.None;
@ -1071,16 +1082,61 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
}
/// <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 IPERL
if (wm != null && wm.OrigCalibFactor == 0 && wm.OrigCalibFactorLNA == 0)
{
wm.OrigCalibFactor = ihead.CalibrationStructV4.Calibration;
wm.OrigCalibFactorLNA = ihead.CalibrationStructV4.CalibrationLNA;
wm.FWVersion = ihead.CalibrationStructV4.FWVersionStr();
}
#endif
resultStr = ihead.CalibrationStructV4.ToString();
error = ihead.VerifyIPerlType() ? CommErr.None : CommErr.WrongIPerlType;
break;
}
}
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="ihead">Water meter object</param>
/// <param name="resultStr">String passed to caller</param>
/// <returns>true on success</returns>
/// <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) return CommErr.CommFailed;
if (ihead.CommFailed || (ihead.CalibrationStruct == null)) return CommErr.CommFailed;
///
/// Parse calibration factor (1 argument) or calibration factor limits (2 arguments)
@ -1202,6 +1258,218 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
}
/// <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.CalibFactorOoRange;
///
/// 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);
#if IPERL
if (wm != null)
{
wm.CalibFactor = newCalibFactor;
wm.CalibFactorLNA = newCalibFactorLNA;
}
#endif
resultStr = ihead.CalibrationStructV4.ToString();
break;
}
}
}
ihead.CalibrationStructV4.Update(data, 2);
ihead.CalibrationStructV4.Update(dataLNA, 34);
}
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>
@ -1210,7 +1478,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
/// <returns>true on success</returns>
static CommErr NormalizeCalibrationFactor(int threadId, IperlHead ihead, Results.Entities.WaterMeter wm, ref string resultStr)
{
if (ihead.CommFailed) return CommErr.CommFailed;
if (ihead.CommFailed || (ihead.CalibrationStruct == null)) return CommErr.CommFailed;
if (ihead.FactorLimitLo <= ihead.CalibFactor && ihead.CalibFactor <= ihead.FactorLimitHi)
{
@ -1223,23 +1491,23 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
CommErr error = CommErr.Write;
/// Determine the new calibration factor
UInt16 newCalibFactor;
UInt16 defaultCalibFactor;
switch (ihead.CalibrationStruct.MeterType)
{
case MeterType.DN15: newCalibFactor = 2710; break;
case MeterType.DN20: newCalibFactor = 3746; break;
case MeterType.DN25: newCalibFactor = 3300; break;
case MeterType.DN32: newCalibFactor = 2500; break;
case MeterType.DN40: newCalibFactor = 3080; break;
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:
newCalibFactor = 3040;
defaultCalibFactor = 3040;
break;
}
byte[] data = new byte[2] { (byte)(newCalibFactor & 0x00FF), (byte)((newCalibFactor >> 8) & 0x00FF) };
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))
@ -1274,6 +1542,78 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
}
/// <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;
}
}
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;
}
}
}
ClosePort(threadId, ihead); /// Close RFID port
return error;
}
const int Hz2CorrFactorsAddr = 0x1875; /// Used by Reset2HzCorrection(...) and Write2HzCorrection(...)
const int Q2CorrFactorsAddr = 0x1878; /// Used by ResetQ2Correction(...) and WriteQ2Correction(...)
@ -1421,10 +1761,16 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
///
if (string.IsNullOrEmpty(q2TestName))
{
/// Use ihead.LastTestResult is no test name is specified as an argument
q2adjResult = ihead.LastTestResult;
q2adjTestData = q2adjResult.TestRslt.TestData;
if (q2adjResult == null || !q2adjResult.TestDone) return CommErr.MissingTest;
/// In case of no test name argument, ihead.LastTestResult is used (if it exists)
if (ihead.LastTestResult != null && ihead.LastTestResult.TestDone)
{
q2adjResult = ihead.LastTestResult;
q2adjTestData = q2adjResult.TestRslt.TestData;
}
else
{
return CommErr.MissingTest;
}
}
else
{

View File

@ -44,25 +44,28 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
if (i == 0)
{
retVal.Add("Read configuration");
retVal.Add("Set Test mode A0");
retVal.Add("Set Test mode A4");
retVal.Add("Read calibration");
retVal.Add("Normalize calibration factor");
retVal.Add("Reset Q2 correction");
retVal.Add("Write calibration factor");
retVal.Add("Write Q2 correction");
retVal.Add("Write Q2 correction Alt");
retVal.Add("Write Q2 correction Greece");
retVal.Add("Write Q2 correction R-L");
retVal.Add("Write Q2 correction L-R");
retVal.Add(iPerlCommunicationForm.ReadConfigurationStr);
retVal.Add(string.Format("{0} A0", iPerlCommunicationForm.SetTestModeStr));
retVal.Add(string.Format("{0} A4", iPerlCommunicationForm.SetTestModeStr));
retVal.Add(iPerlCommunicationForm.ReadCalibrationStr);
retVal.Add(iPerlCommunicationForm.ReadCalibrationV4Str);
retVal.Add(iPerlCommunicationForm.NormalizeCalibrationFactorStr);
retVal.Add(iPerlCommunicationForm.NormalizeCalibrationV4FactorsStr);
retVal.Add(iPerlCommunicationForm.ResetQ2CorrectionStr);
retVal.Add(iPerlCommunicationForm.WriteCalibrationFactorStr);
retVal.Add(iPerlCommunicationForm.WriteCalibrationV4FactorsStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionAltStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionGreeceStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionRLStr);
retVal.Add(iPerlCommunicationForm.WriteQ2CorrectionLRStr);
retVal.Add("Q2 corrected from Q2adj");
retVal.Add("Set Active mode");
retVal.Add(iPerlCommunicationForm.SetActiveModeStr);
retVal.Add("---");
retVal.Add("Reset 2Hz correction");
retVal.Add("Write 2Hz correction");
retVal.Add("Read configuration if enabled");
retVal.Add("Set Test mode 80");
retVal.Add(iPerlCommunicationForm.Reset2HzCorrectionStr);
retVal.Add(iPerlCommunicationForm.Write2HzCorrectionStr);
retVal.Add(string.Format("{0} if enabled", iPerlCommunicationForm.ReadConfigurationStr));
retVal.Add(string.Format("{0} 80", iPerlCommunicationForm.SetTestModeStr));
}
else
{

View File

@ -129,13 +129,13 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
/// <returns>true when successful, false when data are not appropriate</returns>
public bool Update(byte[] data, int offset)
{
if (offset == 2 && data.Length == 2)
if ((data.Length == 2) && (offset == 2))
{
/// Data containing iPerl calibration factor
Calibration = (UInt16)(data[2 - offset] + 256 * data[3 - offset]);
Calibration = (UInt16)(data[0] + 256 * data[1]);
return true;
}
else if (offset == 0 && data.Length == Length)
else if ((data.Length == Length) && (offset == 0))
{
/// Data containing a complete CalibrationStruct
Version = data[0];

View File

@ -0,0 +1,211 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
{
public class CalibrationStructV4
{
public static readonly int Length = 37;
public Byte Version;
public MeterType MeterType;
public UInt16 Calibration;
public VolumeUnits VolumeUnits;
public FlowArrow FlowArrow;
public UInt16 FWVersion;
public UInt16[] TargetField;
public UInt16 RecipMeanCurrent;
public UInt16 ThresholdVolume;
public UInt16 ThresholdTime;
public UInt16 FlowActivationThr;
public UInt16 VolumeArrowThr;
public UInt32 CalibrationTime;
public ulong SerialNumber;
public MeterSealed MeterSealed;
public UInt16 CalibrationLNA;
public byte CheckSum;
public CalibrationStructV4()
{
TargetField = new UInt16[3];
}
public byte[] ToByteArray()
{
byte[] result = new byte[Length];
result[0] = Version;
result[1] = (byte)MeterType;
result[2] = (byte)(Calibration & 0x00FF);
result[3] = (byte)((Calibration >> 8) & 0x00FF);
result[4] = (byte)VolumeUnits;
result[5] = (byte)FlowArrow;
result[6] = (byte)(FWVersion & 0x00FF);
result[7] = (byte)((FWVersion >> 8) & 0x00FF);
result[8] = (byte)( TargetField[0] & 0x00FF);
result[9] = (byte)((TargetField[0] >> 8) & 0x00FF);
result[10] = (byte)( TargetField[1] & 0x00FF);
result[11] = (byte)((TargetField[1] >> 8) & 0x00FF);
result[12] = (byte)( TargetField[2] & 0x00FF);
result[13] = (byte)((TargetField[2] >> 8) & 0x00FF);
result[14] = (byte)(RecipMeanCurrent & 0x00FF);
result[15] = (byte)((RecipMeanCurrent >> 8) & 0x00FF);
result[16] = (byte)(ThresholdVolume & 0x00FF);
result[17] = (byte)((ThresholdVolume >> 8) & 0x00FF);
result[18] = (byte)(ThresholdTime & 0x00FF);
result[19] = (byte)((ThresholdTime >> 8) & 0x00FF);
result[20] = (byte)(FlowActivationThr & 0x00FF);
result[21] = (byte)((FlowActivationThr >> 8) & 0x00FF);
result[22] = (byte)(VolumeArrowThr & 0x00FF);
result[23] = (byte)((VolumeArrowThr >> 8) & 0x00FF);
result[24] = (byte)(CalibrationTime & 0x000000FF);
result[25] = (byte)((CalibrationTime >> 8) & 0x000000FF);
result[26] = (byte)((CalibrationTime >> 16) & 0x000000FF);
result[27] = (byte)((CalibrationTime >> 24) & 0x000000FF);
result[28] = (byte)(SerialNumber & 0x00000000000000FF);
result[29] = (byte)((SerialNumber >> 8) & 0x00000000000000FF);
result[30] = (byte)((SerialNumber >> 16) & 0x00000000000000FF);
result[31] = (byte)((SerialNumber >> 24) & 0x00000000000000FF);
result[32] = (byte)((SerialNumber >> 32) & 0x00000000000000FF);
result[33] = (byte)MeterSealed;
result[34] = (byte)(CalibrationLNA & 0x00FF);
result[35] = (byte)((CalibrationLNA >> 8) & 0x00FF);
result[36] = CheckSum;
return result;
}
/// <summary>
/// Create a calibration structure from a complete byte array
/// </summary>
/// <param name="data">A complete byte array data</param>
/// <returns>CalibrationStructV4 or null when byte array was not complete</returns>
public static CalibrationStructV4 FromByteArray(byte[] data)
{
if (data.Length != Length) return null;
CalibrationStructV4 result = new CalibrationStructV4();
result.Version = data[0];
result.MeterType = (MeterType)data[1];
result.Calibration = (UInt16)(data[2] + 256 * data[3]);
result.VolumeUnits = (VolumeUnits)data[4];
result.FlowArrow = (FlowArrow)data[5];
result.FWVersion = (UInt16)(data[6] + 256 * data[7]);
result.TargetField[0] = (UInt16)(data[8] + 256 * data[9]);
result.TargetField[1] = (UInt16)(data[10] + 256 * data[11]);
result.TargetField[2] = (UInt16)(data[12] + 256 * data[13]);
result.RecipMeanCurrent = (UInt16)(data[14] + 256 * data[15]);
result.ThresholdVolume = (UInt16)(data[16] + 256 * data[17]);
result.ThresholdTime = (UInt16)(data[18] + 256 * data[19]);
result.FlowActivationThr = (UInt16)(data[20] + 256 * data[21]);
result.VolumeArrowThr = (UInt16)(data[22] + 256 * data[23]);
result.CalibrationTime = (((UInt32)data[27] * 256 + data[26]) * 256 + data[25]) * 256 + data[24];
result.SerialNumber = ((((UInt64)data[32] * 256 + data[31]) * 256 + data[30]) * 256 + data[29]) * 256 + data[28];
result.MeterSealed = (MeterSealed)data[33];
result.CalibrationLNA = (UInt16)(data[34] + 256 * data[35]);
result.CheckSum = data[36];
return result;
}
/// <summary>
/// Update the calibration structure from an incomplete byte array
/// </summary>
/// <param name="data">Byte array data</param>
/// <param name="offset">Offset of byte array data in CalibrationStructV2</param>
/// <returns>true when successful, false when data are not appropriate</returns>
public bool Update(byte[] data, int offset)
{
if ((data.Length == 2) && (offset == 2))
{
/// Data containing iPerl calibration factor
Calibration = (UInt16)(data[0] + 256 * data[1]);
return true;
}
else if ((data.Length == 2) && (offset == 34))
{
/// Data containing iPerl calibration factor
CalibrationLNA = (UInt16)(data[0] + 256 * data[1]);
return true;
}
else if ((data.Length == Length) && (offset == 0))
{
/// Data containing a complete CalibrationStruct
Version = data[0];
MeterType = (MeterType)data[1];
Calibration = (UInt16)(data[2] + 256 * data[3]);
VolumeUnits = (VolumeUnits)data[4];
FlowArrow = (FlowArrow)data[5];
FWVersion = (UInt16)(data[6] + 256 * data[7]);
TargetField[0] = (UInt16)(data[8] + 256 * data[9]);
TargetField[1] = (UInt16)(data[10] + 256 * data[11]);
TargetField[2] = (UInt16)(data[12] + 256 * data[13]);
RecipMeanCurrent = (UInt16)(data[14] + 256 * data[15]);
ThresholdVolume = (UInt16)(data[16] + 256 * data[17]);
ThresholdTime = (UInt16)(data[18] + 256 * data[19]);
FlowActivationThr = (UInt16)(data[20] + 256 * data[21]);
VolumeArrowThr = (UInt16)(data[22] + 256 * data[23]);
CalibrationTime = (((UInt32)data[27] * 256 + data[26]) * 256 + data[25]) * 256 + data[24];
SerialNumber = ((((UInt64)data[32] * 256 + data[31]) * 256 + data[30]) * 256 + data[29]) * 256 + data[28];
MeterSealed = (MeterSealed)data[33];
CalibrationLNA = (UInt16)(data[34] + 256 * data[35]);
CheckSum = data[36];
return true;
}
else
return false;
}
public string FWVersionStr()
{
int d1 = (FWVersion >> 8) & 0x000F;
int d2 = (FWVersion >> 12) & 0x000F;
int d3 = (FWVersion >> 4) & 0x000F;
int d4 = FWVersion & 0x000F;
return string.Format("{0}.{1}{2}{3}", d1, d2, d3, d4);
}
public override string ToString()
{
return string.Format("Calibration: V{0} Type={1} Cal={2} Units={3} FlowArrow.{4} FW={5} Hi={6} Norm={7} Low={8} RMC={9} ThrVol={10} ThrTime={11} FlActThr={12} VolArrThr={13} CalTm={14} SN={15} MeterSealed={16} CalLNA={17} Chksum={18}",
Version,
MeterType,
Calibration,
VolumeUnits,
FlowArrow,
FWVersion,
TargetField[0],
TargetField[1],
TargetField[2],
RecipMeanCurrent,
ThresholdVolume,
ThresholdTime,
FlowActivationThr,
VolumeArrowThr,
CalibrationTime,
SerialNumber,
MeterSealed,
CalibrationLNA,
CheckSum.ToString("X2"));
}
}
}

View File

@ -114,8 +114,28 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
}
CalibrationStruct calibrationStruct;
/// <summary> CalibrationStruct of the water meter obtained or updated by iPerlCommunication </summary>
public CalibrationStructV4 CalibrationStructV4
{
get { return calibrationStructV4; }
set { calibrationStructV4 = value; }
}
CalibrationStructV4 calibrationStructV4;
public ushort OrigCalibFactor;
public ushort CalibFactor { get { return (CalibrationStruct != null) ? CalibrationStruct.Calibration : (ushort)0; } }
public ushort CalibFactor
{
get
{
return (CalibrationStruct != null) ? CalibrationStruct.Calibration
: ((CalibrationStructV4 != null) ? CalibrationStructV4.Calibration
: (ushort)0);
}
}
public ushort OrigCalibFactorLNA;
public ushort CalibFactorLNA { get { return (CalibrationStructV4 != null) ? CalibrationStructV4.CalibrationLNA : (ushort)0; } }
public double Q2ErrWOCorrection;
public bool Q2CorrectionDone;
@ -127,7 +147,15 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
public bool Hz2CorrectionDone;
public int Hz2Correction;
public string FWVersion { get { return (CalibrationStruct != null) ? CalibrationStruct.FWVersionStr() : string.Empty; } }
public string FWVersion
{
get
{
return (CalibrationStruct != null) ? CalibrationStruct.FWVersionStr()
: ((CalibrationStructV4 != null) ? CalibrationStructV4.FWVersionStr()
: string.Empty);
}
}
/// <summary> Result of the last test used to calculate Q2 correction factors, etc </summary>
@ -395,11 +423,13 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
configStruct = null;
calibrationStruct = null;
calibrationStructV4 = null;
LastTestResult = null;
NominalTestFlowLph = 0;
OrigCalibFactor = 0;
OrigCalibFactorLNA = 0;
Q2ErrWOCorrection = 0;
Q2CorrectionDone = false;
Q2CorrRFlow = 0;
@ -428,7 +458,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
/// Prepare serial port
optoSerialPort = new SerialPort(string.Format("COM{0}", iperlHeadCfg.OptoComPortNr),
9600, Parity.None, 8, StopBits.One);
9600, Parity.None, 8, StopBits.One);
optoSerialPort.Handshake = Handshake.None;
optoSerialPort.Open();

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("2.18.1001.0")]
[assembly: AssemblyFileVersion("2.18.1001.0")]
[assembly: AssemblyVersion("2.18.1004.0")]
[assembly: AssemblyFileVersion("2.18.1004.0")]

View File

@ -1134,6 +1134,7 @@
</Compile>
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlEnums.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\CalibrationStruct.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\CalibrationStructV4.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\ConfigStruct.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\Enums.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\Factory.cs" />