Merge branch 'main' of https://slm.sms-esaap.com/la_operations/laa_production
This commit is contained in:
@@ -216,9 +216,11 @@
|
||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="EventArguments\CalibDataEventArgs.cs" />
|
||||
<Compile Include="EventArguments\BendDetectDataEventArgs.cs" />
|
||||
<Compile Include="EventArguments\FlowDataEventArgs.cs" />
|
||||
<Compile Include="EventArguments\RegisterUpdateEventArgs.cs" />
|
||||
<Compile Include="EventArguments\RequestResponseDataEventArgs.cs" />
|
||||
<Compile Include="MeasurementRecords\BendDetectionRecord.cs" />
|
||||
<Compile Include="MeasurementRecords\CalibrationRecord.cs" />
|
||||
<Compile Include="MeasurementRecords\FlowTestRecord.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using Xylem.Common.Hardware.Interfaces.Protocols.ProtocolCore.EventArguments;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.MeasurementRecords;
|
||||
|
||||
|
||||
namespace Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.EventArguments
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class BendDetectDataEventArgs : BaseDataEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// new record from Stream
|
||||
/// </summary>
|
||||
public BendDetectionRecord NewData;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Object GetEventData()
|
||||
{
|
||||
return NewData;
|
||||
}
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using Xylem.Common.Metrology.Measurements;
|
||||
|
||||
namespace Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.MeasurementRecords
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Streaming record for protocol M (information about bend detection and correction)
|
||||
/// </summary>
|
||||
public class BendDetectionRecord : MeasurementRecord
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The status of the U0 detection for this measurement
|
||||
/// </summary>
|
||||
public enum StatusBendU0Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// Status okay
|
||||
/// </summary>
|
||||
OKAY = 0,
|
||||
/// <summary>
|
||||
/// Error code as defined by field name
|
||||
/// </summary>
|
||||
ERROR_GENESISFLOW_INSTALLATION_HIGH_TIME_DIFF = 0x0F41,
|
||||
/// <summary>
|
||||
/// Error code as defined by field name
|
||||
/// </summary>
|
||||
ERROR_GENESISFLOW_INSTALLATION_LOW_FLOW_IGNORE = 0x0F42,
|
||||
/// <summary>
|
||||
/// Error code as defined by field name
|
||||
/// </summary>
|
||||
ERROR_GENESISFLOW_INSTALLATION_BAD_CHANNELS = 0x0F43,
|
||||
/// <summary>
|
||||
/// Error code as defined by field name
|
||||
/// </summary>
|
||||
ERROR_GENESISFLOW_INSTALLATION_FIXED = 0x0F44
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An enum describing the installation type detected
|
||||
/// </summary>
|
||||
public enum InstallationTypeEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// Installation type code as defined by field name
|
||||
/// </summary>
|
||||
INSTALLATION_U0_180_360 = 0,
|
||||
/// <summary>
|
||||
/// Installation type code as defined by field name
|
||||
/// </summary>
|
||||
INSTALLATION_U0_90_270 = 1,
|
||||
/// <summary>
|
||||
/// Installation type code as defined by field name
|
||||
/// </summary>
|
||||
INSTALLATION_UNDISTURBED = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Status of U0 Bend detection
|
||||
/// </summary>
|
||||
public StatusBendU0Enum StatusBendU0;
|
||||
|
||||
/// <summary>
|
||||
/// Installation type code
|
||||
/// </summary>
|
||||
public InstallationTypeEnum InstallationType;
|
||||
|
||||
/// <summary>
|
||||
/// The proportion of the installation correction to apply based on the detected
|
||||
/// installation. 100% == 0x8000
|
||||
/// </summary>
|
||||
public Double CorrectionFactor_percent;
|
||||
|
||||
/// <summary>
|
||||
/// The default proportion of the installation correction to apply based on the
|
||||
/// detected installation. 100% == 0x8000
|
||||
/// </summary>
|
||||
private const UInt32 DefaultCorrectionFactor = 0x8000;
|
||||
|
||||
/// <summary>
|
||||
/// Scale for correction factor to apply to convert it to percentage value 100% == 0x8000
|
||||
/// </summary>
|
||||
public const Double CorrectionFactorScale = 100.0 / DefaultCorrectionFactor;
|
||||
|
||||
/// <summary>
|
||||
/// The volume in internal units before correction applied
|
||||
/// </summary>
|
||||
public Double PreCorrectionVolumeRaw;
|
||||
|
||||
/// <summary>
|
||||
/// The volume in internal units after correction applied
|
||||
/// </summary>
|
||||
public Double PostCorrectionVolumeRaw;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get result as string
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override String ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($"Status={StatusBendU0}").Append(",")
|
||||
.Append($"Installation={InstallationType}").Append(",")
|
||||
.Append($"Factor={CorrectionFactor_percent}").Append(",")
|
||||
.Append($"PreVolume={PreCorrectionVolumeRaw}").Append(",")
|
||||
.Append($"PostVolume={PostCorrectionVolumeRaw}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Consts
|
||||
/// </summary>
|
||||
public enum LedMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Test mode with raw record to log.
|
||||
/// Should give one <see cref="FlowTestRecord"/>
|
||||
/// 3 times <see cref="CalibrationRecord"/> and
|
||||
/// one <see cref="BendDetectionRecord"/>
|
||||
/// </summary>
|
||||
FlowTestAndCalibDataAndBendCorrect = 7,
|
||||
/// <summary>
|
||||
/// Test mode with raw record to log. Should give one <see cref="FlowTestRecord"/>
|
||||
/// 3 times <see cref="CalibrationRecord"/> and repeat this till led mode is switch
|
||||
|
||||
@@ -369,6 +369,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
|
||||
#region state machine and states
|
||||
|
||||
/// <summary>
|
||||
/// Order number under which this meter has to be produced
|
||||
/// </summary>
|
||||
public Int32 OrderNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Radio address
|
||||
/// </summary>
|
||||
public Int64 RadioAddress;
|
||||
|
||||
/// <summary>
|
||||
/// do not use it to set ProcessStatus
|
||||
/// if you want to change ProcessStatus of this genesis use <see cref="ProcessStatus" />
|
||||
@@ -1316,9 +1326,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
/// <remarks date="2023-Nov-27" author="Thomas Wiedebusch">
|
||||
/// - Remind installed FW version of FLEXNETVERSION for StoreAllConfigurations.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Dec-08..11" author="Thomas Wiedebusch">
|
||||
/// - Avoid multiple assignment of identical register in dictionary as the configuration.json may overlap
|
||||
/// on some versions. If one register has been added, this passed the test and is valid for this FW.
|
||||
/// It has to be avoided to have the register multiple times as it may cause unpredictable assignments
|
||||
/// of values to one and reading and compare from another which doesn't have a value!
|
||||
/// </remarks>
|
||||
private void ReadMeterFirmwareAndAssignRegisters()
|
||||
{
|
||||
//avoid overwriting of list if this already exits
|
||||
// Avoid overwriting of list if this already exits
|
||||
if (MeterAppListVersion.Any())
|
||||
{
|
||||
_logger.Warn($"Slot:{Slot} - Trying to override meter dictionary. Skip read out FW");
|
||||
@@ -1388,7 +1404,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
ReadRegister(Register.System.MetrologyUpgradePermission));
|
||||
|
||||
//read core revision
|
||||
var coreRegisterRead = RegisterConverter.ConvertTo<String>(ReadRegister(Register.System.CoreRevision, 16));
|
||||
var coreRegisterRead = RegisterConverter.ConvertTo<String>(ReadRegister(Register.System.CoreRevision));
|
||||
CoreRevision = null;
|
||||
if (!string.IsNullOrEmpty(coreRegisterRead))
|
||||
{
|
||||
@@ -1437,23 +1453,27 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
{
|
||||
var currentGroup = MeterAppListVersion.First(f => f.AppId == registerToCheck.Key.AppAddress);
|
||||
|
||||
if (!registerToCheck.Key.RegisterDetail.Version.First.HasValue &&
|
||||
!registerToCheck.Key.RegisterDetail.Version.Last.HasValue)
|
||||
{
|
||||
//TODO legacy to collect not clear specified registers
|
||||
registerToCheck.Key.IsAvailable = true;
|
||||
_configRegister.MeterRegisterDic.TryAdd(registerToCheck.Key, null);
|
||||
if (registerToCheck.Key?.RegisterDetail?.Version == null)
|
||||
continue;
|
||||
}
|
||||
if (registerToCheck.Key.RegisterDetail.Version.Last != null &&
|
||||
registerToCheck.Key.RegisterDetail.Version.First != null &&
|
||||
registerToCheck.Key.RegisterDetail.Version.First.Value <= currentGroup.Version &&
|
||||
registerToCheck.Key.RegisterDetail.Version.Last.Value >= currentGroup.Version)
|
||||
|
||||
if (// Legacy registers may not have an version assigned
|
||||
(!registerToCheck.Key.RegisterDetail.Version.First.HasValue &&
|
||||
!registerToCheck.Key.RegisterDetail.Version.Last.HasValue) ||
|
||||
// Normal version assignment with first and last value
|
||||
(registerToCheck.Key.RegisterDetail.Version.Last != null &&
|
||||
registerToCheck.Key.RegisterDetail.Version.First != null &&
|
||||
registerToCheck.Key.RegisterDetail.Version.First.Value <= currentGroup.Version &&
|
||||
registerToCheck.Key.RegisterDetail.Version.Last.Value >= currentGroup.Version))
|
||||
{
|
||||
registerToCheck.Key.IsAvailable = true;
|
||||
// Avoid multiple assignment of identical register in dictionary if one has passed the test
|
||||
if (_configRegister.MeterRegisterDic.Any(reg =>
|
||||
reg.Key.GetIdent().Equals(registerToCheck.Key.GetIdent())))
|
||||
continue;
|
||||
_configRegister.MeterRegisterDic.TryAdd(registerToCheck.Key, null);
|
||||
registerToCheck.Key.IsAvailable = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var checkMinRegister in Register.GetMinRequiredRegisters())
|
||||
{
|
||||
if (_configRegister.MeterRegisterDic.All(a => a.Key.GetIdent() != checkMinRegister))
|
||||
@@ -1472,8 +1492,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
_logger.Warn(ex, $"Slot:{Slot} - Not able to set minimum list of registers. check json file for {checkMinRegister} ");
|
||||
_logger.Warn(ex.Message, $"Slot:{Slot} - Unable to set minimum list of registers. Check json file for {checkMinRegister} ");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2204,7 +2223,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
a.Key.RegisterName.ToLower() == "storeconfiguration" ||
|
||||
a.Key.RegisterName.ToLower() == "storecalibration"))
|
||||
{
|
||||
if (!a.Key.IsAvailable) continue;
|
||||
if (!a.Key.IsAvailable)
|
||||
continue;
|
||||
|
||||
// retries for each register access
|
||||
var retriesLeft = 2;
|
||||
@@ -2234,10 +2254,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
a.Key.RegisterName.ToLower() == "storeconfiguration" ||
|
||||
a.Key.RegisterName.ToLower() == "storecalibration"))
|
||||
{
|
||||
if (!a.Key.IsAvailable) continue;
|
||||
if (!a.Key.IsAvailable)
|
||||
continue;
|
||||
|
||||
// For R1.2.x the read back is corrected
|
||||
if ( InstalledFwVersion < 1200 && (a.Key.AppName == "SENSUSRADIO" || a.Key.AppName == "NA2WALARMS"))
|
||||
if (InstalledFwVersion < 1200 && (a.Key.AppName == "SENSUSRADIO" || a.Key.AppName == "NA2WALARMS"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -165,6 +165,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
//the DecodeMsg has assigned either a DataCalib or DataFlowTest data set
|
||||
var calibrationRecord = sd.DataCalib;
|
||||
var flowTestRecord = sd.DataFlowTest;
|
||||
var bendDetectRecord = sd.DataBendDetectTest;
|
||||
|
||||
if (flowTestRecord != null)
|
||||
{
|
||||
@@ -172,6 +173,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bendDetectRecord != null)
|
||||
{
|
||||
TotalValidationWithoutErrorsCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (calibrationRecord != null)
|
||||
{
|
||||
if (calibrationRecord.Validation == 0)
|
||||
|
||||
@@ -58,7 +58,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
|
||||
/// <summary>
|
||||
/// List for parameters which need to be removed from parameter list
|
||||
/// if meter has radio
|
||||
/// </summary>
|
||||
public static readonly List<String> ProhibitedParameters = new List<String>
|
||||
{
|
||||
@@ -66,7 +65,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
};
|
||||
/// <summary>
|
||||
/// List for un-reversed parameters, all others need to be swapped byte-wise
|
||||
/// if meter has radio
|
||||
/// </summary>
|
||||
public static readonly List<String> UnRevertedParameters = new List<String>
|
||||
{
|
||||
@@ -75,6 +73,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
"METROLOGYASST_FlowPoint"
|
||||
};
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static readonly List<String> ExcludedFromCompareParameters = new List<String>
|
||||
{
|
||||
"SENSUSRADIO_UpgFWVersion" // After a FW-Update the FW version has changed and the compare will fail
|
||||
};
|
||||
/// <summary>
|
||||
/// Pre programming parameters for all devices defined here, will be filled with radio parameters
|
||||
/// if meter has radio
|
||||
/// </summary>
|
||||
@@ -383,6 +388,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
/// <remarks date="2023-Nov-20" author="Thomas Wiedebusch">
|
||||
/// - Initial.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Nov-28" author="Thomas Wiedebusch">
|
||||
/// - Compare registers reactivated based on new interface (configuration.json) with new
|
||||
/// "StaticType": “approximate”.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Dec-08" author="Thomas Wiedebusch">
|
||||
/// - Removed <see cref="ExcludedFromCompareParameters"/> as those will change on e.g. FW update.
|
||||
/// </remarks>
|
||||
public Boolean CompareRegisters()
|
||||
{
|
||||
if (_pcbIdFinalRegisterRead != _pcbIdInitialRegisterRead ||
|
||||
@@ -396,6 +408,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
|
||||
// build a string list of the registers being able to sort those
|
||||
var registerNames = _restoreRegisters.MeterRegisterDic.Select(register => register.Key.GetIdent()).ToList();
|
||||
// Remove all excluded registers
|
||||
foreach (var regName in ExcludedFromCompareParameters.Where(regName => registerNames.Any(reg => reg == regName)))
|
||||
{
|
||||
registerNames.Remove(regName);
|
||||
}
|
||||
// sort the list of register names
|
||||
registerNames.Sort();
|
||||
// limit the count to 1 to avoid division by zero
|
||||
@@ -425,17 +442,65 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
var strRequiredRegisterValue = "";
|
||||
try
|
||||
{
|
||||
var isIdentical = true;
|
||||
for (var c = 0; c < dataSize; c++)
|
||||
var isApproximated = false;
|
||||
var isIdentical = false;
|
||||
if (regDef.RegisterDetail.StaticType == StaticType.ReadBackApproximated)
|
||||
{
|
||||
if (restorableRawRegister[c] == finalReadRawRegister[c]) continue;
|
||||
isIdentical = false;
|
||||
break;
|
||||
Int64 restoreValue = 0;
|
||||
Int64 finalValue = 0;
|
||||
if (regDef.DataType.Name.Equals("Int32"))
|
||||
{
|
||||
restoreValue = RegisterConverter.ConvertTo<Int32>(restorableRawRegister);
|
||||
finalValue = RegisterConverter.ConvertTo<Int32>(finalReadRawRegister);
|
||||
}
|
||||
else if (regDef.DataType.Name.Equals("UInt32"))
|
||||
{
|
||||
restoreValue = RegisterConverter.ConvertTo<UInt32>(restorableRawRegister);
|
||||
finalValue = RegisterConverter.ConvertTo<UInt32>(finalReadRawRegister);
|
||||
}
|
||||
// Just half of number range will work due to cast to Int64
|
||||
else if (regDef.DataType.Name.Equals("UInt64"))
|
||||
{
|
||||
restoreValue = (Int64)RegisterConverter.ConvertTo<UInt64>(restorableRawRegister);
|
||||
finalValue = (Int64)RegisterConverter.ConvertTo<UInt64>(finalReadRawRegister);
|
||||
}
|
||||
else if (regDef.DataType.Name.Equals("Int64"))
|
||||
{
|
||||
restoreValue = RegisterConverter.ConvertTo<UInt32>(restorableRawRegister);
|
||||
finalValue = RegisterConverter.ConvertTo<UInt32>(finalReadRawRegister);
|
||||
}
|
||||
else if (regDef.DataType.Name.Equals("Byte"))
|
||||
{
|
||||
restoreValue = RegisterConverter.ConvertTo<Byte>(restorableRawRegister);
|
||||
finalValue = RegisterConverter.ConvertTo<Byte>(finalReadRawRegister);
|
||||
}
|
||||
else if (regDef.DataType.Name.Equals("SByte"))
|
||||
{
|
||||
restoreValue = RegisterConverter.ConvertTo<SByte>(restorableRawRegister);
|
||||
finalValue = RegisterConverter.ConvertTo<SByte>(finalReadRawRegister);
|
||||
}
|
||||
// Check limited to +/- 3
|
||||
if (restoreValue - 3 <= finalValue && restoreValue + 3 >= finalValue)
|
||||
{
|
||||
isApproximated = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var c = 0; c < dataSize; c++)
|
||||
{
|
||||
if (restorableRawRegister[c] != finalReadRawRegister[c])
|
||||
{
|
||||
isIdentical = false;
|
||||
break;
|
||||
}
|
||||
isIdentical = true;
|
||||
}
|
||||
}
|
||||
// convert register content to text with raw and converted value depending on data type
|
||||
strRequiredRegisterValue =
|
||||
RegisterConverter.GetRegisterContentText(regDef, restorableRawRegister);
|
||||
if (finalReadRawRegister != null && isIdentical)
|
||||
if (finalReadRawRegister != null && (isIdentical || isApproximated))
|
||||
{
|
||||
strRequiredRegisterValue += $" - {Resources.StrRegisterCompareSucceeded}";
|
||||
}
|
||||
@@ -458,7 +523,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
}
|
||||
finally
|
||||
{
|
||||
var actualProcessMsg = $"{Resources.StrRegisterCompare}: {strRequiredRegisterValue} ";
|
||||
var actualProcessMsg = string.IsNullOrEmpty(strRequiredRegisterValue) ? "":
|
||||
$"{Resources.StrRegisterCompare}: {strRequiredRegisterValue} ";
|
||||
|
||||
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs($@"{Resources.StrRegisterCompare}" +
|
||||
$@" {ActualRegisterCtr} / {registersCount}",
|
||||
@@ -497,16 +563,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
|
||||
/// <remarks date="2023-Nov-21" author="Thomas Wiedebusch">
|
||||
/// - Return false if PcbId between initial- and final-read does NOT match return false.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Nov-30" author="Thomas Wiedebusch">
|
||||
/// - Allow final read out as often as called even if done before.
|
||||
/// </remarks>
|
||||
public Boolean FinalReadRegisters()
|
||||
{
|
||||
if (_currentGenesis == null)
|
||||
return false;
|
||||
|
||||
// deny update of registers if already done
|
||||
if (_pcbIdFinalRegisterRead == _currentGenesis.PcbId)
|
||||
return true;
|
||||
|
||||
_pcbIdFinalRegisterRead = _currentGenesis.PcbId;
|
||||
_pcbIdFinalRegisterRead = _currentGenesis.PcbId;
|
||||
// clear the contents of the restore registers if the water meter backed up was not identical
|
||||
if (_pcbIdInitialRegisterRead != _pcbIdFinalRegisterRead)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -29,6 +29,22 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol
|
||||
private const Double AmplitudeToVoltFactor = 1.0 / 0x400000 / 1000.0; // 2^22 100 0000 0000 0000 0000 0000b
|
||||
private const Double PulseWidthToRelFactor = 1.0 / 0x100; // 2^8
|
||||
|
||||
/// <summary>
|
||||
/// Default data for bend detection tests of Genesis
|
||||
/// </summary>
|
||||
private readonly BendDetectionRecord _bendDetectionDefault = new BendDetectionRecord
|
||||
{
|
||||
StatusBendU0 = BendDetectionRecord.StatusBendU0Enum.OKAY,
|
||||
InstallationType = BendDetectionRecord.InstallationTypeEnum.INSTALLATION_UNDISTURBED,
|
||||
CorrectionFactor_percent = 0.0,
|
||||
PreCorrectionVolumeRaw = 0.0,
|
||||
PostCorrectionVolumeRaw = 0.0,
|
||||
TimeS = 0.0,
|
||||
OverflowTimeS = CpuTimeOverflowS,
|
||||
Crc = 0xFFFF,
|
||||
IsValid = false
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Default data for flow tests of Genesis
|
||||
/// </summary>
|
||||
@@ -76,6 +92,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol
|
||||
|
||||
private CalibrationRecord _dataCalibRec;
|
||||
private FlowTestRecord _dataFlowTestRec;
|
||||
private BendDetectionRecord _dataBendDetectRec;
|
||||
private readonly Boolean _ignoreCorruptedData;
|
||||
|
||||
/// <summary>
|
||||
@@ -85,6 +102,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol
|
||||
{
|
||||
_dataFlowTestRec = _dataDefault;
|
||||
_dataCalibRec = _rawDataDefault;
|
||||
_dataBendDetectRec = _bendDetectionDefault;
|
||||
_ignoreCorruptedData = ignoreCorruptedData;
|
||||
}
|
||||
|
||||
@@ -104,6 +122,14 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bend detection test data
|
||||
/// </summary>
|
||||
public BendDetectionRecord DataBendDetectTest
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decoding the raw message
|
||||
/// </summary>
|
||||
@@ -112,6 +138,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol
|
||||
/// <remarks date="2023-Mar-09" author="T.Wiedebusch">
|
||||
/// - Modified using common CRC check before branching to the protocol specific decoder.
|
||||
/// </remarks>
|
||||
/// <remarks date="2023-Dec-06" author="T.Wiedebusch">
|
||||
/// - Introduced protocol 'm' for bending detection.
|
||||
/// </remarks>
|
||||
public Boolean DecodeMsg(String rawMsg)
|
||||
{
|
||||
var rawRecordIsValid = false;
|
||||
@@ -170,7 +199,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol
|
||||
|
||||
switch (rawMsgFields[0])
|
||||
{
|
||||
case "@f":
|
||||
case "@m":
|
||||
_dataBendDetectRec.IsValid = rawRecordIsValid;
|
||||
if (rawRecordIsValid || !_ignoreCorruptedData)
|
||||
{
|
||||
DecodeProtocolM(ref _dataBendDetectRec, rawMsgFields);
|
||||
DataBendDetectTest = _dataBendDetectRec;
|
||||
}
|
||||
break;
|
||||
|
||||
case "@f":
|
||||
_dataFlowTestRec.IsValid = rawRecordIsValid;
|
||||
if (rawRecordIsValid || !_ignoreCorruptedData)
|
||||
{
|
||||
@@ -205,6 +243,44 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol
|
||||
return rawRecordIsValid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracting message from string fields for protocol 'm'
|
||||
/// </summary>
|
||||
/// <param name="dataBendTestRec">reference to bend detection test record</param>
|
||||
/// <param name="fields">Separated fields containing the measurement as string</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks date="2023-Mar-09" author="T.Wiedebusch">
|
||||
/// - Modified using common CRC check in advance.
|
||||
/// </remarks>
|
||||
private static void DecodeProtocolM(ref BendDetectionRecord dataBendTestRec, IList<String> fields)
|
||||
{
|
||||
// time stamp attachment
|
||||
dataBendTestRec.DecodedTime = DateTimeOffset.UtcNow;
|
||||
|
||||
// extract received CRC
|
||||
dataBendTestRec.Crc = ushort.Parse(fields[(Int32)ProtMsubString.Crc],
|
||||
NumberStyles.HexNumber);
|
||||
// extract the status
|
||||
dataBendTestRec.StatusBendU0 =
|
||||
(BendDetectionRecord.StatusBendU0Enum)UInt32.Parse(fields[(Int32)ProtMsubString.Status],
|
||||
NumberStyles.AllowHexSpecifier);
|
||||
// extract the installation type
|
||||
dataBendTestRec.InstallationType =
|
||||
(BendDetectionRecord.InstallationTypeEnum)UInt32.Parse(fields[(Int32)ProtMsubString.Installation],
|
||||
NumberStyles.AllowHexSpecifier);
|
||||
// extract the correction factor in percent
|
||||
dataBendTestRec.CorrectionFactor_percent =
|
||||
UInt32.Parse(fields[(Int32)ProtMsubString.Factor],
|
||||
NumberStyles.AllowHexSpecifier) * BendDetectionRecord.CorrectionFactorScale;
|
||||
|
||||
// build result values, the volume before and after correction can be positive or negative!
|
||||
dataBendTestRec.PreCorrectionVolumeRaw = Int32.Parse(fields[(Int32)ProtMsubString.PreVolume],
|
||||
NumberStyles.AllowHexSpecifier);
|
||||
// build result values, the volume before and after correction can be positive or negative!
|
||||
dataBendTestRec.PostCorrectionVolumeRaw = Int32.Parse(fields[(Int32)ProtMsubString.PostVolume],
|
||||
NumberStyles.AllowHexSpecifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracting message from string fields for protocol 'f'
|
||||
/// </summary>
|
||||
@@ -413,6 +489,18 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol
|
||||
CpuTime,
|
||||
Crc
|
||||
}
|
||||
/// field position in protocol 'm'
|
||||
private enum ProtMsubString
|
||||
{
|
||||
//do not remove this needed for position in record
|
||||
ProtType,
|
||||
Status,
|
||||
Installation,
|
||||
Factor,
|
||||
PreVolume,
|
||||
PostVolume,
|
||||
Crc
|
||||
}
|
||||
|
||||
/// field position in protocol 'g'
|
||||
private enum ProtGsubString
|
||||
|
||||
@@ -73,6 +73,27 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol
|
||||
}
|
||||
|
||||
}
|
||||
else if (_streamingDecode.DataBendDetectTest != null)
|
||||
{
|
||||
_streamingDecode.DataBendDetectTest.SyncMarkRecord = dataArgs.GetSyncMarkRecord();
|
||||
_streamingDecode.DataBendDetectTest.ReceivedTime = dataArgs.GetReceivedTime();
|
||||
if (_streamingDecode.DataBendDetectTest.IsValid)
|
||||
{
|
||||
OnRecordIsDecoded?.Invoke(this, new BendDetectDataEventArgs
|
||||
{
|
||||
NewData = _streamingDecode.DataBendDetectTest,
|
||||
RawData = data
|
||||
});
|
||||
}
|
||||
else if (!_ignoreCorruptedData)
|
||||
{
|
||||
OnRecordIsDecoded?.Invoke(this, new BendDetectDataEventArgs
|
||||
{
|
||||
NewData = _streamingDecode.DataBendDetectTest,
|
||||
RawData = data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//toDo: handle trashy telegrams
|
||||
}
|
||||
|
||||
@@ -26,19 +26,25 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes
|
||||
/// <summary>
|
||||
/// Static type to define restore capability
|
||||
/// </summary>
|
||||
private const String RestoreRequired = "static";
|
||||
public const String RestoreRequired = "static";
|
||||
|
||||
/// <summary>
|
||||
/// Static type approximate informs that the read back value may be not identical
|
||||
/// to the written value and is approximated.
|
||||
/// </summary>
|
||||
public const String ReadBackApproximated = "approximate";
|
||||
|
||||
/// <summary>
|
||||
/// Denied restore capability
|
||||
/// </summary>
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
private const String RestoreDenied = "dynamic";
|
||||
public const String RestoreDenied = "dynamic";
|
||||
|
||||
/// <summary>
|
||||
/// Unpredictable restore capability
|
||||
/// </summary>
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
private const String RestoreUnpredictable = "infrequentlyupdated";
|
||||
public const String RestoreUnpredictable = "infrequentlyupdated";
|
||||
|
||||
/// <summary>
|
||||
/// Check restore capability
|
||||
@@ -46,7 +52,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes
|
||||
/// <returns>true if restore required</returns>
|
||||
public Boolean CheckRestoreCapability()
|
||||
{
|
||||
return StaticTypeValue == RestoreRequired;
|
||||
return StaticTypeValue == RestoreRequired || StaticTypeValue == ReadBackApproximated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user