ProductionUiCordonel: - restore listed registers after reboot which didn't survive the reboot

This commit is contained in:
Thomas Wiedebusch 2025-11-17 17:01:39 +01:00
parent fc9f20814c
commit 8dd636922b
7 changed files with 218 additions and 72 deletions

View File

@ -47,6 +47,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// </summary>
public List<RecoveryRegisterItem> RecoveryRegisters;
/// <summary>
/// Name of registers which should be restored after reboot if the compare failed.
/// </summary>
private List<RecoveryRegisterItem> _restoreRegistersAfterReboot;
/// <summary>
/// Marker for restore after reboot parameters
/// </summary>
public Boolean HasRestoreRegistersAfterRebootIfCompareFailed;
/// <summary>
/// Register content on initial connect to keep those during update
/// </summary>
@ -100,6 +110,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
"SENSUSRADIO_UpgFWVersion" // After a FW-Update the FW version has changed
};
/// <summary>
/// Registers manually explicit marked to be restored after reboot if compare failed. Those registers will
/// temporary setup values which do not survive a reboot. This is done to overcome a FW-bug which overwrites
/// those values after the reboot procedure!
/// </summary>
private static readonly List<String> _restoreAfterRebootIfCompareFailed = new List<String>
{
"CUSTOMER_AlarmEnableMask" // Restored to hard coded value up to FW R1.4.22
};
/// <summary>
/// Registers manually explicit excluded for in-field updatable parameters for the CUST to prevent inadvertent
/// modifications resulting in potential MID violations.
@ -120,7 +140,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
"FLEXNETSERIAL_FwdlState",
"FLEXNETSERIAL_UpgState",
"GENESISFLOW_AmplitudePeakDetectEnd", // 1
"GENESISFLOW_ArrowThreshold", // 2
"GENESISFLOW_CalFactor1", // 3
@ -206,7 +226,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
"PERIODICLOG_PeriodicLogLifeTimeCounter",
"PERIODICLOG_ResetCounter",
"POWERMON_TotalUsedCharge",
"POWERMON_TotalUsedCharge",
"POWERMON_TotalUsedSeconds",
"SENSUSRADIO_AverageFlowPeriod", // 1
@ -360,6 +380,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
_currentGenesis = currentGenesis;
RecoveryRegisters = null;
RecoveryRegisters = new List<RecoveryRegisterItem>();
_restoreRegistersAfterReboot = new List<RecoveryRegisterItem>();
}
/// <summary>
@ -556,7 +577,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
continue;
}
// Fill DEBUG lists START with all registers even if they are multiple assigned
// Fill DEBUG lists START with all registers even if they are multiple assigned
sortableRegisterList.Add(proPar.RegisterName);
switch (proPar.Source)
@ -572,21 +593,21 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
break;
}
// Take this parameter as is
//TODO THW take configuration.json and use for String and Array type, see RegisterConverter
//take the register properties from configuration.json
//get the pre-defined dictionary
//var meterRegisters = MockGenesis based on FW version .GetConfigRegistersDefinitions();
//var regDef = meterRegisters.GetRegisterDefinitionByName(proPar.RegisterName);
//if (regDef.DataType.Name.Equals("Int32"))
//{
// Add parameter if it is not in the list
//if (sortableProgrammingParameters.All(a => !proPar.RegisterName.Equals(a.RegisterName)))
//{
// sortableProgrammingParameters.Add(proPar);
// continue;
//}
//}
// Take this parameter as is
//TODO THW take configuration.json and use for String and Array type, see RegisterConverter
//take the register properties from configuration.json
//get the pre-defined dictionary
//var meterRegisters = MockGenesis based on FW version .GetConfigRegistersDefinitions();
//var regDef = meterRegisters.GetRegisterDefinitionByName(proPar.RegisterName);
//if (regDef.DataType.Name.Equals("Int32"))
//{
// Add parameter if it is not in the list
//if (sortableProgrammingParameters.All(a => !proPar.RegisterName.Equals(a.RegisterName)))
//{
// sortableProgrammingParameters.Add(proPar);
// continue;
//}
//}
@ -780,7 +801,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
return StatusReturn.Failed;
}
return RawProgrammingParametersFilterAndSort(programmingParameters, recoveryRegistersDb, out errorMsg,
return RawProgrammingParametersFilterAndSort(programmingParameters, recoveryRegistersDb, out errorMsg,
fieldUpdate);
}
catch (Exception)
@ -819,7 +840,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <remarks date="2025-Apr-07" author="Thomas Wiedebusch">
/// - CancellationToken.
/// </remarks>
public StatusReturn EolProgrammingRegisters(List<RecoveryRegisterItem> recoveryRegistersDb,
public StatusReturn EolProgrammingRegisters(List<RecoveryRegisterItem> recoveryRegistersDb,
CancellationToken cancellationToken)
{
// Mark field update as false to set EOL as true to force accu reset
@ -926,7 +947,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// - Remove '_fieldUpdateBlacklist' parameters for the CUST to prevent inadvertent modifications resulting in potential
/// MID violations.
/// </remarks>
public StatusReturn WriteRegisters(List<RecoveryRegisterItem> recoveryRegistersDb, CancellationToken cancellationToken,
/// <remarks date="2025-Nov-17" author="Thomas Wiedebusch">
/// - Login/Logout moved to <see cref="WriteRegisterParameterSet"/>.
/// </remarks>
public StatusReturn WriteRegisters(List<RecoveryRegisterItem> recoveryRegistersDb, CancellationToken cancellationToken,
Boolean fieldUpdate)
{
if (_currentGenesis == null ||
@ -952,11 +976,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
_dbParameterRegisterList = recoveryRegistersDb.Select(register => register.RegisterIdent).ToList();
_dbParameterRegisterList.Sort();
// write values to Genesis
_currentGenesis.ReLogin();
if (!_currentGenesis.IsLoggedOn)
return StatusReturn.Failed;
// get the pre-defined dictionary
var meterRegisters = _currentGenesis.GetConfigRegistersDefinitions();
@ -991,11 +1010,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(Resources.StrRegisterRecoveryPreparation,
actualProcessMessage: Resources.StrRegisterRecoveryPreparation));
if (StatusReturn.Failed == WriteRegisterParameterSet(_prepareProgramming, recRegistersCount, meterRegisters,
if (StatusReturn.Failed == WriteRegisterParameterSet(_prepareProgramming, recRegistersCount, meterRegisters,
cancellationToken, fieldUpdate))
{
// the logout will force the radio app to activate the settings
_currentGenesis?.Logout();
return StatusReturn.Failed;
}
@ -1003,32 +1020,25 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(Resources.StrRegisterRecoveryExec,
actualProcessMessage: Resources.StrRegisterRecoveryExec));
if (StatusReturn.Failed == WriteRegisterParameterSet(recoveryRegistersDb, recRegistersCount, meterRegisters,
if (StatusReturn.Failed == WriteRegisterParameterSet(recoveryRegistersDb, recRegistersCount, meterRegisters,
cancellationToken, fieldUpdate))
{
// the logout will force the radio app to activate the settings
_currentGenesis?.Logout();
return StatusReturn.Failed;
return StatusReturn.Failed;
}
// finalize recovery
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(Resources.StrRegisterRecoveryFinalization,
actualProcessMessage: Resources.StrRegisterRecoveryFinalization));
if (StatusReturn.Failed == WriteRegisterParameterSet(finalizeProgrammingAll, recRegistersCount, meterRegisters,
if (StatusReturn.Failed == WriteRegisterParameterSet(finalizeProgrammingAll, recRegistersCount, meterRegisters,
cancellationToken, fieldUpdate))
{
// the logout will force the radio app to activate the settings
_currentGenesis?.Logout();
return StatusReturn.Failed;
}
// remind pcbId of this run to avoid endless repetition
_pcbIdWriteRegisters = _currentGenesis.PcbId;
// the logout will force the radio app to activate the settings
_currentGenesis?.Logout();
// Wait for completion as storing may need a certain time
Thread.Sleep(1000);
@ -1062,19 +1072,20 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <remarks date="2025-Jul-22" author="Thomas Wiedebusch">
/// - Excluded un-comparable registers from write turned back on ('blind' writing enabled again).
/// </remarks>
private StatusReturn WriteRegisterParameterSet(List<RecoveryRegisterItem> recoveryRegistersDb, Int32 recRegistersCount,
MeterRegisters meterRegisters, CancellationToken cancellationToken, Boolean fieldUpdate)
/// <remarks date="2025-Nov-17" author="Thomas Wiedebusch">
/// - Login/Logout moved here.
/// </remarks>
private StatusReturn WriteRegisterParameterSet(List<RecoveryRegisterItem> recoveryRegistersDb,
Int32 recRegistersCount, MeterRegisters meterRegisters, CancellationToken cancellationToken, Boolean fieldUpdate)
{
_currentGenesis.ReLogin();
if (!_currentGenesis.IsLoggedOn)
return StatusReturn.Failed;
foreach (var recReg in recoveryRegistersDb)
{
//TODO THW Check
// Temporary excluded un-comparable registers from write as this make no sense to write them blind being
// unable to read the correct value back.
//if (_excludedFromCompareParameters.Any( regName => recReg.RegisterIdent.Equals(regName)))
// continue;
// Remove all parameters from parameter list if used for field update
if (fieldUpdate && _fieldUpdateBlacklist.Any( regName => recReg.RegisterIdent.Equals(regName)))
if (fieldUpdate && _fieldUpdateBlacklist.Any(regName => recReg.RegisterIdent.Equals(regName)))
continue;
_actualRegisterCtr++;
@ -1099,6 +1110,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
$@"{Resources.StrWriteRegister} {_actualRegisterCtr} / {recRegistersCount}",
overallProcessCtrPercent, Resources.StrErrorMsgRegisterNotFound + " Register: " +
recReg.RegisterIdent));
_currentGenesis?.Logout();
return StatusReturn.Failed;
}
@ -1115,6 +1127,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(
$@"{Resources.StrWriteRegister} {_actualRegisterCtr} / {recRegistersCount}",
overallProcessCtrPercent, Resources.StrRegisterValueOutOfRange + " " + errorMessage));
_currentGenesis?.Logout();
return StatusReturn.Failed;
}
@ -1124,6 +1137,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
$@"{Resources.StrWriteRegister} {_actualRegisterCtr} / {recRegistersCount}",
overallProcessCtrPercent, Resources.StrErrorMsgRegisterWrite + " Register: " +
recReg.RegisterIdent));
_currentGenesis?.Logout();
return StatusReturn.Failed;
}
@ -1149,10 +1163,63 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
if (cancellationToken.IsCancellationRequested)
break;
}
_currentGenesis?.Logout();
return StatusReturn.Okay;
}
/// <summary>
/// Restore and compare all registers which did not survive a reboot and are listed in the
/// <see cref="_restoreAfterRebootIfCompareFailed"/>
/// - This is a workaround for a FW-bug in R1.4.22 and below.
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <remarks date="2025-Nov-17" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
public Boolean RestoreAndCompareRegistersAfterReboot(CancellationToken cancellationToken)
{
if (!HasRestoreRegistersAfterRebootIfCompareFailed)
return false;
HasRestoreRegistersAfterRebootIfCompareFailed = false;
// Use preset recovery registers for check
RecoveryRegisters.Clear();
RecoveryRegisters.AddRange(_restoreRegistersAfterReboot);
_failedComparisonRegisters.Clear();
// get the pre-defined dictionary
var meterRegisters = _currentGenesis.GetConfigRegistersDefinitions();
_actualRegisterCtr = 0;
// Expected access counter is 3 times the content for write, read and compare
var maxCounter = 3 * RecoveryRegisters.Count;
// Write after reboot
if (StatusReturn.Failed == WriteRegisterParameterSet(RecoveryRegisters, maxCounter,
meterRegisters, cancellationToken, false))
{
return false;
}
// executes login read logout
if (!ReadPresetRegisters(cancellationToken))
{
return false;
}
// Compare register content
if (!CompareRegisters(cancellationToken))
{
return false;
}
// Wait for completion as storing may need a certain time
Thread.Sleep(1000);
return true;
}
/// <summary>
/// Compare all registers which can be restored without new access to meter.
/// Precondition:
@ -1203,6 +1270,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <remarks date="2025-Aug-12" author="Thomas Wiedebusch">
/// - Take 'null' in readBack into account due to communication error.
/// </remarks>
/// <remarks date="2025-Nov-17" author="Thomas Wiedebusch">
/// - _restoreAfterRebootIfCompareFailed.
/// </remarks>
/// <remarks date="2025-Nov-17" author="Thomas Wiedebusch">
/// - Made method static.
/// </remarks>
public Boolean CompareRegisters(CancellationToken cancellationToken)
{
if (_pcbIdFinalRegisterRead != _pcbIdWriteRegisters ||
@ -1214,6 +1287,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
// DEBUG
_failedComparisonRegisters?.Clear();
_restoreRegistersAfterReboot.Clear();
// build a string list of the registers being able to sort those
var registerNames = RecoveryRegisters.Select(register => register.RegisterIdent).ToList();
@ -1263,14 +1337,14 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
var writtenValue = recReg.WriteValue;
var readBackValue = recReg.ReadBackValue;
var strRequiredRegisterValue = "";
var isApproximated = false;
var isIdentical = false;
try
{
// ATTENTION: The size of the writtenValue and readBackValue may deviate!
var dataSize = writtenValue.Length;
var isApproximated = false;
var isIdentical = false;
// Process values only if not 'null'
if (writtenValue != null && readBackValue != null)
{
@ -1331,15 +1405,21 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
}// Process register values only if not 'null'
// convert register content to text with raw and converted value depending on data type
strRequiredRegisterValue =
RegisterConverter.GetRegisterContentText(regDef, writtenValue);
// Convert register content to text with raw and converted value depending on data type
strRequiredRegisterValue = RegisterConverter.GetRegisterContentText(regDef, writtenValue);
if (readBackValue != null && (isIdentical || isApproximated))
{
strRequiredRegisterValue += $" - {Resources.StrRegisterCompareSucceeded}";
}
else
{
// Check registers which should be restored after reboot if failed
if (_restoreAfterRebootIfCompareFailed.Any(reg => reg.Equals(regName)))
{
HasRestoreRegistersAfterRebootIfCompareFailed = true;
_restoreRegistersAfterReboot.Add(recReg);
}
var encryptRawData = regName.Contains("EncryptionKey") || regName.Contains("Password");
var strReadBackRegisterValue = RegisterConverter.GetRegisterRawText(regDef, readBackValue,
@ -1366,7 +1446,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
{
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs($@"{Resources.StrRegisterCompare}" +
$@" {_actualRegisterCtr} / {registersCount}",
overallProcessCtrPercent, actualProcessMsg));
overallProcessCtrPercent, actualProcessMsg,
statusReturn: isIdentical || isApproximated ? StatusReturn.Okay : StatusReturn.Failed));
}
}
@ -1427,7 +1508,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
Boolean retVal;
try
{
// create a dictionary for final read being able to compare those with the initial read and restored
if (!BuildReadableRegisterDictionary(ref _finalRegisters))
return false;
@ -1525,8 +1605,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
// remind the PCB ID before update for comparison
_pcbIdInitialRegisterRead = _currentGenesis.PcbId;
// create the dictionaries out of the configuration.json
if (!BuildReadableRegisterDictionary(ref _initialRegisters))
// create a dictionary for final read being able to compare those with the initial read and restored
if (!BuildReadableRegisterDictionary(ref _finalRegisters))
return false;
// log to report file the initial register read string
@ -1559,14 +1639,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <remarks date="2024-Feb-23" author="Thomas Wiedebusch">
/// - Excluded registers which do not contain useful information.
/// </remarks>
/// <remarks date="2025-Nov-17" author="Thomas Wiedebusch">
/// - Sequence resorted.
/// </remarks>
public Boolean BuildReadableRegisterDictionary(ref List<RecoveryRegisterItem> registers)
{
if (_currentGenesis == null || registers == null)
return false;
registers.Clear();
_readableRegisterList.Clear();
// get the pre-defined dictionary
var meterRegisters = _currentGenesis.GetConfigRegistersDefinitions();
// extract all registers which can be read and create two dictionaries for before update to safe program
@ -1579,11 +1660,14 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
{
var registerIdent = reg.Key.GetIdent();
registers.Add(new RecoveryRegisterItem(registerIdent, reg.Value));
_readableRegisterList.Add(registerIdent);
}
_readableRegisterList.Sort();
registers.Sort((a, b) => String.Compare(a.RegisterIdent, b.RegisterIdent, StringComparison.Ordinal));
// DEBUG information
_readableRegisterList.Clear();
_readableRegisterList.AddRange(_finalRegisterList);
return registers.Count > 0;
}
@ -1612,7 +1696,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
// temporary list of registers just for read and log without keeping them alive
var registers = new List<RecoveryRegisterItem>();
if (!BuildReadableRegisterDictionary(ref registers))
// create a dictionary for final read being able to compare those with the initial read and restored
if (!BuildReadableRegisterDictionary(ref _finalRegisters))
return false;
// log to report file the initial register read string
@ -1692,7 +1777,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <remarks date="2025-Oct-13" author="Thomas Wiedebusch">
/// - Date size directly from register object.
/// </remarks>
private Boolean ReadRegistersSet(ref List<RecoveryRegisterItem> registers, CancellationToken cancellationToken)
private Boolean ReadRegistersSet(ref List<RecoveryRegisterItem> registers, CancellationToken cancellationToken)
{
if (_currentGenesis == null)
return false;

View File

@ -520,10 +520,27 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
/// <remarks date="2024-Jan-17" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2025-Nov-17" author="Thomas Wiedebusch">
/// - StatusReturn.
/// </remarks>
protected void ProcessUpdate_Handler(Object sender, ProcessExecEventArgs e)
{
ActualProcessProgress++;
LogNewStatusMsg(e.ActualProcessMessage);
switch (e.StatusReturn)
{
case StatusReturn.Okay:
SuccessMsgDispatcher(e.ActualProcessMessage);
break;
case StatusReturn.Warning:
WarningMsgDispatcher(e.ActualProcessMessage);
break;
case StatusReturn.Failed:
ErrorMsgDispatcher(e.ActualProcessMessage);
break;
default:
LogNewStatusMsg(e.ActualProcessMessage);
break;
}
}
/// <summary>

View File

@ -49,6 +49,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
/// <remarks date="2025-Apr-07" author="Thomas Wiedebusch">
/// - CancellationToken.
/// </remarks>
/// <remarks date="2025-Nov-17" author="Thomas Wiedebusch">
/// - Restore registers after reboot if failed - temporary workaround for FW-bug.
/// </remarks>
public override StatusReturn ExecuteProcess()
{
// Uncheck executed process to leave the result open needed for retries
@ -98,6 +101,24 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
Meter?.Logout();
return StatusReturn.Okay;
}
// Restore registers after reboot if failed
if (RegisterRestorer.HasRestoreRegistersAfterRebootIfCompareFailed)
{
// Write and compare those registers
RegisterRestorer.OnProcessUpdate += ProcessUpdate_Handler;
retValBol = RegisterRestorer.RestoreAndCompareRegistersAfterReboot(CancellationToken);
RegisterRestorer.OnProcessUpdate -= ProcessUpdate_Handler;
if (retValBol)
{
WarningMsgDispatcher(Resources.StrWarningMsgParameterCompare);
EolProgress.ParametrizationCompareChecked = EOLStatus.OK;
Meter?.Logout();
return StatusReturn.Warning;
}
}
// No chance to repair anything
EolProgress.ParametrizationCompareChecked = EOLStatus.FAIL;
Meter?.Logout();
return StatusReturn.Failed;

View File

@ -2509,7 +2509,16 @@ namespace Xylem.Common.Production.ProductionUiCordonel.Properties {
}
/// <summary>
/// Looks up a localized string similar to WARNING: Inspect results.
/// Looks up a localized string similar to WARNING: Parameter restored after reboot as it does not survive it.
/// </summary>
internal static string StrWarningMsgParameterCompare {
get {
return ResourceManager.GetString("StrWarningMsgParameterCompare", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to WARNING: Result needs inspection! Process.
/// </summary>
internal static string StrWarningMsgProcess {
get {

View File

@ -660,6 +660,9 @@
</data>
<data name="StrErrorMsgParameterCompare" xml:space="preserve">
<value>FEHLER: Parametervergleich fehlgeschlagen</value>
</data>
<data name="StrWarningMsgParameterCompare" xml:space="preserve">
<value>WARNUNG: Parameter überlebte den Neustart nicht und wurde danach wiederhergestellt</value>
</data>
<data name="StrErrorMsgParameterWrite" xml:space="preserve">
<value>FEHLER: Parameterschreiben fehlgeschlagen</value>
@ -677,7 +680,7 @@
<value>WARNUNG</value>
</data>
<data name="StrWarningMsgProcess" xml:space="preserve">
<value>WARNUNG: Ergebnis manuell überprüfen</value>
<value>WARNUNG: Ergebnis muß überprüft werden! Prozeß </value>
</data>
<data name="StrProcessStateAttention" xml:space="preserve">
<value>ACHTUNG</value>

View File

@ -660,6 +660,9 @@
</data>
<data name="StrErrorMsgParameterCompare" xml:space="preserve">
<value>ERROR: Parameter compare failed</value>
</data>
<data name="StrWarningMsgParameterCompare" xml:space="preserve">
<value>WARNING: Parameter restored after reboot as it does not survive it</value>
</data>
<data name="StrErrorMsgParameterWrite" xml:space="preserve">
<value>ERROR: Parameter write failed</value>
@ -675,12 +678,12 @@
</data>
<data name="StrProcessStateWarning" xml:space="preserve">
<value>WARNING</value>
</data>
<data name="StrWarningMsgProcess" xml:space="preserve">
<value>WARNING: Result needs inspection! Process</value>
</data>
<data name="StrProcessStateAttention" xml:space="preserve">
<value>ATTENTION</value>
</data>
<data name="StrWarningMsgProcess" xml:space="preserve">
<value>WARNING: Inspect results</value>
</data>
<data name="StrLblSpecialRequirement" xml:space="preserve">
<value>SPECIAL APPROVAL</value>

View File

@ -1,4 +1,5 @@
using System;
using Xylem.Common.CommonCore.Consts;
namespace Xylem.Common.Utils.ProcessExec.EventArguments
{
@ -28,6 +29,11 @@ namespace Xylem.Common.Utils.ProcessExec.EventArguments
/// </summary>
public Double? ActualProcessPercent { get; }
/// <summary>
/// Single process percentage 0..100
/// </summary>
public StatusReturn StatusReturn { get; }
/// <summary>
/// Ctor
/// </summary>
@ -35,9 +41,10 @@ namespace Xylem.Common.Utils.ProcessExec.EventArguments
/// <param name="overallProcessPercent"></param>
/// <param name="actualProcessMessage"></param>
/// <param name="actualProcessPercent"></param>
/// <param name="statusReturn"></param>
public ProcessExecEventArgs(String overallProcessMessage,
Double? overallProcessPercent = null, String actualProcessMessage = null,
Double? actualProcessPercent = null)
Double? actualProcessPercent = null, StatusReturn statusReturn = StatusReturn.Unknown)
{
OverallProcessMessage = overallProcessMessage;
ActualProcessMessage = actualProcessMessage;
@ -45,6 +52,7 @@ namespace Xylem.Common.Utils.ProcessExec.EventArguments
OverallProcessPercent = OverallProcessPercent < 0 ? 0 : OverallProcessPercent;
ActualProcessPercent = actualProcessPercent > 100.0 ? 100.0 : actualProcessPercent;
ActualProcessPercent = ActualProcessPercent < 0 ? 0 : ActualProcessPercent;
StatusReturn = statusReturn;
}
}
}