diff --git a/Common/Common.sln.DotSettings.user b/Common/Common.sln.DotSettings.user
index 080ddbbc..9a455621 100644
--- a/Common/Common.sln.DotSettings.user
+++ b/Common/Common.sln.DotSettings.user
@@ -28,7 +28,7 @@
True
NewVersion
True
- C:\Users\Thomas\AppData\Local\Temp\JetBrains\ReSharperPlatformVs15\vAny_33007af5\CoverageData\_Common.-1885154465\Snapshot\snapshot.utdcvr
+
diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs b/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs
index f88d37e9..1865b93c 100644
--- a/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs
+++ b/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs
@@ -1,13 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Newtonsoft.Json;
+using Xylem.Common.CommonCore.Configuration;
using Xylem.Common.CommonCore.Consts;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes;
using Xylem.Common.Logic.ProductionOrderCore;
+using Xylem.Common.Logic.SoftwareAccessHelper;
using Xylem.Common.Utils.ProcessExec;
using Xylem.Common.Utils.ProcessExec.EventArguments;
+using Access = Xylem.Common.Hardware.WaterMeter.Genesis.Registers.Access;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
{
@@ -57,16 +61,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
public event EventHandler OnProcessUpdate;
///
- /// List for parameters which need to be removed from parameter list
+ /// List for parameters which need to be removed from parameter list as they mustn't be accessed
///
- public static readonly List ProhibitedParameters = new List
+ private static readonly List _prohibitedParameters = new List
{
"CUSTOMER_AppArrangement"
};
///
/// List for un-reversed parameters, all others need to be swapped byte-wise
///
- public static readonly List UnRevertedParameters = new List
+ private static readonly List _unRevertedParameters = new List
{
"SENSUSRADIO_EncryptionKey",
"GENESISFLOW_DisplayPow10",
@@ -75,7 +79,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
///
///
///
- public static readonly List ExcludedFromCompareParameters = new List
+ private static readonly List _excludedFromCompareParameters = new List
{
"SENSUSRADIO_UpgFWVersion" // After a FW-Update the FW version has changed and the compare will fail
};
@@ -83,7 +87,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// Pre programming parameters for all devices defined here, will be filled with radio parameters
/// if meter has radio
///
- public static readonly List PrepareProgramming = new List
+ private static readonly List _prepareProgramming = new List
{
// The display needs to be unsealed for change of unit and resolution
new ProgrammingParameters("GENESISFLOW_SealDisplay", new Byte[] { 0x00 })
@@ -92,7 +96,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
///
/// Post programming parameters for radio only
///
- public static readonly List FinalizeProgrammingRadioOnly = new List
+ private static readonly List _finalizeProgrammingRadioOnly = new List
{
new ProgrammingParameters("LOGGER_TriggerLogFlush", new Byte[] { 0x01 }),
new ProgrammingParameters("PERIODICLOG_ResetCounter", new Byte[] { 0x00 }),
@@ -105,12 +109,21 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
///
/// Post programming parameters for all devices
///
- public static readonly List FinalizeProgramming = new List
+ private static readonly List _finalizeProgramming = new List
{
new ProgrammingParameters("GENESISFLOW_SealDisplay", new Byte[] { 0x01 }),
new ProgrammingParameters("GENESISFLOW_TriggerIdle", new Byte[] { 0x00 }),
};
+ ///
+ /// Post programming parameters for EOL (end of line, prepare for shipping workplace)
+ ///
+ private static readonly List _finalizeProgrammingEol = new List
+ {
+ new ProgrammingParameters("GENESISFLOW_ResetAccumulators", new Byte[] { 0x01 }),
+ new ProgrammingParameters("NFC_EraseRMA", new Byte[] { 0x01 })
+ };
+
///
/// Actual Port Counter
///
@@ -147,6 +160,108 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
_currentGenesis = genesisMeter;
}
+ ///
+ /// Collect programming parameters from DB.
+ ///
+ ///
+ ///
+ /// recovery registers
+ ///
+ /// - Initial.
+ ///
+ ///
+ /// - Sort the registers from DB but keep the PrepareProgramming and FinalizeProgramming in the required sequence.
+ ///
+ ///
+ /// - Removed preparation and finalization of register recovery to remove sequencing as this will be done in the
+ /// RegisterRestorer by the FwUpdateSw worker giving the ability to log this in the report.
+ ///
+ ///
+ /// - Data base access imported to have a common interface for programming parameters for EOL (shipping) and CUST.
+ ///
+ public static Boolean DownloadProgrammingParametersFromDb(String pcbId, out List recoveryRegisters)
+ {
+ recoveryRegisters = new List();
+ try
+ {
+ var url = $"{ServiceUrls.GenesisFinalCheckServiceUrl()}GetProgrammingParameters?PcbID={pcbId}";
+ var ppJson = LocalWebRequest.GetRequest(url, 30000);
+
+ if (string.IsNullOrEmpty(ppJson))
+ {
+ return false;
+ }
+
+ var programmingParameters = JsonConvert.DeserializeObject>(ppJson);
+ if (programmingParameters == null || programmingParameters.Count == 0)
+ {
+ return false;
+ }
+
+ // Temporary storage for sorting before assembling those registers with the preparation and
+ // finalization of programming and therefore building a sequence
+ var sortableProgrammingParameters = new List();
+
+ foreach (var proPar in programmingParameters)
+ {
+ // reverse byte order for all parameters except those listed below
+ if (!string.IsNullOrEmpty(proPar.RegisterName))
+ {
+ // ATTENTION: These parameters are coming out of the DB and need to be removed from list
+ if (RegisterRestorer._prohibitedParameters.Contains(proPar.RegisterName))
+ {
+ }
+ // ATTENTION: These parameters are coming out of the DB in wrong order
+ if (RegisterRestorer._unRevertedParameters.Contains(proPar.RegisterName))
+ {
+ // skip VAKO if equally register is set in CSD or on read only access
+ if (proPar.Source == ProgrammingSource.Vako && sortableProgrammingParameters.Any(a =>
+ a.Source == ProgrammingSource.Csd && proPar.RegisterName.Equals(a.RegisterName)))
+ continue;
+ sortableProgrammingParameters.Add(proPar);
+ }
+ else
+ {
+ // skip VAKO if equally register is set in CSD or on read only access
+ if (proPar.Source == ProgrammingSource.Vako && sortableProgrammingParameters.Any(a =>
+ a.Source == ProgrammingSource.Csd && proPar.RegisterName.Equals(a.RegisterName)))
+ continue;
+ sortableProgrammingParameters.Add(new ProgrammingParameters(proPar.RegisterName,
+ proPar.RegisterValue.Reverse().ToArray(), proPar.Source));
+ }
+ } // register for this FW is defined
+ else
+ {
+ return false;
+ }
+ }
+
+ // Sort the programming parameters coming from DB (VAKO/CSD)
+ sortableProgrammingParameters.Sort((x, y) => string.Compare(x.RegisterName, y.RegisterName,
+ StringComparison.Ordinal));
+
+ // convert to RecoveryRegisterItem
+ if (sortableProgrammingParameters.Count > 0)
+ {
+ foreach (var proPar in sortableProgrammingParameters)
+ {
+ var recReg = new RecoveryRegisterItem
+ {
+ RegisterIdent = proPar.RegisterName,
+ WriteValue = proPar.RegisterValue
+ };
+ recoveryRegisters.Add(recReg);
+ }
+ }
+
+ return true;
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+
///
/// Avoid doubling of register restore on subsequent FW-Update trials.
///
@@ -183,15 +298,28 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
///
- /// Recover all registers set from caller in the original sequence as they may prepare and finalize
- /// settings.
- ///
- /// ATTENTION:
- /// Do NOT sort the recovery registers as those needed to be executed in the correct sequence,
- /// as those are preparing the meter to a special mode to take the values and finalize the settings.
- ///
+ /// EOL (end of line) programming contains a reset of the accumulators. Else it is identical with recover
+ /// registers.
///
- /// list of registers to update
+ /// list of registers to update from data base without special sequence
+ ///
+ /// true if setup succeeded
+ ///
+ /// - Initial.
+ ///
+ public Boolean EolProgrammingRegisters(List recoveryRegistersDb)
+ {
+ // mark EOL as true to force Accu reset
+ return RecoverRegisters(recoveryRegistersDb, true);
+ }
+
+ ///
+ /// Recover all registers set from caller. Additional preparation and finalization will be added.
+ /// settings.
+ ///
+ /// list of registers to update from data base without special sequence
+ ///
+ /// EOL (end of line) programming with accu reset
/// true if restoring succeeded
///
/// - Initial.
@@ -210,16 +338,21 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
///
/// - Logging of some exception messages.
///
- public Boolean RecoverRegisters(List recoveryRegisters)
+ ///
+ /// - EOL sequence for accumulators reset,
+ /// - Remind pcbId as already recovered before the true return,
+ /// - Exclude lock of repeated execution for EOL.
+ ///
+ public Boolean RecoverRegisters(List recoveryRegistersDb, Boolean eolProgramming = false)
{
if (_currentGenesis == null ||
string.IsNullOrEmpty(_currentGenesis.PcbId) ||
- recoveryRegisters == null ||
- recoveryRegisters.Count == 0)
+ recoveryRegistersDb == null ||
+ recoveryRegistersDb.Count == 0)
return false;
- // if already recovered skip this with positive feedback
- if (_currentGenesis.PcbId == _pcbIdRecoveryRegisters)
+ // if not EOL processing and already recovered skip this with positive feedback
+ if (!eolProgramming && _currentGenesis.PcbId == _pcbIdRecoveryRegisters)
return true;
// remind pcbId of this run to avoid endless repetition
@@ -238,21 +371,25 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
// prepare list for finalization depending on SENSUSRADIO installation
var finalizeProgrammingAll = new List();
- finalizeProgrammingAll.AddRange(FinalizeProgramming);
- if (recoveryRegisters.Any(x => x.RegisterIdent.Contains("SENSUSRADIO")))
+ if (recoveryRegistersDb.Any(x => x.RegisterIdent.Contains("SENSUSRADIO")))
{
- finalizeProgrammingAll.AddRange(FinalizeProgrammingRadioOnly);
+ finalizeProgrammingAll.AddRange(_finalizeProgrammingRadioOnly);
}
+ // add EOL sequence if called
+ if (eolProgramming)
+ finalizeProgrammingAll.AddRange(_finalizeProgrammingEol);
+ // standard end of programming sequence
+ finalizeProgrammingAll.AddRange(_finalizeProgramming);
// set the process counter
- var recRegistersCount = recoveryRegisters.Count > 0 ? recoveryRegisters.Count : 1;
- recRegistersCount += PrepareProgramming.Count;
+ var recRegistersCount = recoveryRegistersDb.Count > 0 ? recoveryRegistersDb.Count : 1;
+ recRegistersCount += _prepareProgramming.Count;
recRegistersCount += finalizeProgrammingAll.Count;
// prepare recovery
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(Resources.StrRegisterRecoveryPreparation,
actualProcessMessage: Resources.StrRegisterRecoveryPreparation));
- foreach (var prepRecReg in PrepareProgramming)
+ foreach (var prepRecReg in _prepareProgramming)
{
ActualRegisterCtr++;
var overallProcessCtrPercent = 100.0 * ActualRegisterCtr / recRegistersCount;
@@ -294,7 +431,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
// register recovery
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(Resources.StrRegisterRecoveryExec,
actualProcessMessage: Resources.StrRegisterRecoveryExec));
- foreach (var recReg in recoveryRegisters)
+ foreach (var recReg in recoveryRegistersDb)
{
ActualRegisterCtr++;
var overallProcessCtrPercent = 100.0 * ActualRegisterCtr / recRegistersCount;
@@ -378,6 +515,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
}// finalize recovery
+ // remind pcbId of this run to avoid endless repetition
+ _pcbIdRecoveryRegisters = _currentGenesis.PcbId;
+
_currentGenesis?.Logout();
return true;
}
@@ -397,7 +537,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// "StaticType": “approximate”.
///
///
- /// - Removed as those will change on e.g. FW update.
+ /// - Removed as those will change on e.g. FW update.
///
///
/// - Avoid message event if message is empty.
@@ -416,7 +556,7 @@ 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)))
+ foreach (var regName in _excludedFromCompareParameters.Where(regName => registerNames.Any(reg => reg == regName)))
{
registerNames.Remove(regName);
}
@@ -442,7 +582,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
// take the size into account as a read value will be filled up to a chunk of 4 bytes
var dataSize = RegisterConverter.SizeOf(regDef);
-
+
if (restorableRawRegister == null)
continue;
@@ -499,7 +639,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
if (restorableRawRegister[c] != finalReadRawRegister[c])
{
isIdentical = false;
- break;
+ break;
}
isIdentical = true;
}
@@ -581,7 +721,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
if (_currentGenesis == null)
return false;
- _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)
{
diff --git a/ServiceFwUpdate/Common/FwUpdateDb/FwUpdateDb.cs b/ServiceFwUpdate/Common/FwUpdateDb/FwUpdateDb.cs
index 648e210d..66487988 100644
--- a/ServiceFwUpdate/Common/FwUpdateDb/FwUpdateDb.cs
+++ b/ServiceFwUpdate/Common/FwUpdateDb/FwUpdateDb.cs
@@ -13,7 +13,6 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
-using Xylem.Common.Logic.ProductionOrderCore;
using Xylem.Common.Logic.ProductionOrderCore.FW;
using Xylem.Common.Logic.SoftwareAccessHelper;
using Xylem.Common.Utils.DateTimeServer;
@@ -35,14 +34,6 @@ namespace Xylem.ServiceFwUpdate.Common.FwUpdateDb
get; private set;
}
- ///
- /// Programming parameters from DB.
- ///
- public List DbProgrammingParameters
- {
- get; private set;
- }
-
///
/// Complete information of all builder operators registered in DB.
///
@@ -255,6 +246,7 @@ namespace Xylem.ServiceFwUpdate.Common.FwUpdateDb
return false;
}
}
+
///
/// Collect programming parameters from DB.
///
@@ -271,99 +263,19 @@ namespace Xylem.ServiceFwUpdate.Common.FwUpdateDb
/// - Removed preparation and finalization of register recovery to remove sequencing as this will be done in the
/// RegisterRestorer by the FwUpdateSw worker giving the ability to log this in the report.
///
+ ///
+ /// - Use common interface for programming parameters for EOL (shipping) and CUST from .
+ ///
public Boolean DownloadCordonelRecoveryRegistersFromDb(String pcbId, out List recoveryRegisters)
{
- recoveryRegisters = new List();
- try
- {
- var url = $"{ServiceUrls.GenesisFinalCheckServiceUrl()}GetProgrammingParameters?PcbID={pcbId}";
- var csdRet = LocalWebRequest.GetRequest(url, 30000);
-
- if (string.IsNullOrEmpty(csdRet))
- {
- DbIsConnected = false;
- return false;
- }
-
- var programmingParameters = JsonConvert.DeserializeObject>(csdRet);
- if (programmingParameters == null || programmingParameters.Count == 0)
- {
- return false;
- }
-
- DbIsConnected = true;
-
- // Temporary storage for sorting before assembling those registers with the preparation and
- // finalization of programming and therefore building a sequence
- var sortableProgrammingParameters = new List();
-
- foreach (var proPar in programmingParameters)
- {
- // reverse byte order for all parameters except those listed below
- if (!string.IsNullOrEmpty(proPar.RegisterName))
- {
- // ATTENTION: These parameters are coming out of the DB and need to be removed from list
- if (RegisterRestorer.ProhibitedParameters.Contains(proPar.RegisterName))
- {
- }
- // ATTENTION: These parameters are coming out of the DB in wrong order
- if (RegisterRestorer.UnRevertedParameters.Contains(proPar.RegisterName))
- {
- // skip VAKO if equally register is set in CSD or on read only access
- if (proPar.Source == ProgrammingSource.Vako && sortableProgrammingParameters.Any(a =>
- a.Source == ProgrammingSource.Csd && proPar.RegisterName.Equals(a.RegisterName)))
- continue;
- sortableProgrammingParameters.Add(proPar);
- }
- else
- {
- // skip VAKO if equally register is set in CSD or on read only access
- if (proPar.Source == ProgrammingSource.Vako && sortableProgrammingParameters.Any(a =>
- a.Source == ProgrammingSource.Csd && proPar.RegisterName.Equals(a.RegisterName)))
- continue;
- sortableProgrammingParameters.Add(new ProgrammingParameters(proPar.RegisterName,
- proPar.RegisterValue.Reverse().ToArray(), proPar.Source));
- }
- } // register for this FW is defined
- else
- {
- return false;
- }
- }
-
- // Sort the programming parameters coming from DB (VAKO/CSD)
- sortableProgrammingParameters.Sort(( x,y) => string.Compare(x.RegisterName, y.RegisterName,
- StringComparison.Ordinal));
-
- // Clean or create new programming parameters
- DbProgrammingParameters?.Clear();
- if (DbProgrammingParameters == null)
- DbProgrammingParameters = new List();
-
- // Add the settings which should be dispatched to the meter to reconfigure it
- DbProgrammingParameters.AddRange(sortableProgrammingParameters);
-
- // convert to RecoveryRegisterItem
- if (DbProgrammingParameters.Count > 0)
- {
- foreach (var proPar in DbProgrammingParameters)
- {
- var recReg = new RecoveryRegisterItem
- {
- RegisterIdent = proPar.RegisterName,
- WriteValue = proPar.RegisterValue
- };
- recoveryRegisters.Add(recReg);
- }
- }
-
- return true;
- }
- catch (Exception)
+ if (!RegisterRestorer.DownloadProgrammingParametersFromDb(pcbId, out recoveryRegisters))
{
DbIsConnected = false;
return false;
}
+
+ DbIsConnected = true;
+ return true;
}
///
@@ -908,7 +820,7 @@ namespace Xylem.ServiceFwUpdate.Common.FwUpdateDb
DbIsConnected = true;
DbCordonelCustomerOrders =
JsonConvert.DeserializeObject>(requestResponse);
- DbCordonelCustomerOrders?.Sort( (a, b) => a.CustomerOrderNumber.CompareTo(b.CustomerOrderNumber));
+ DbCordonelCustomerOrders?.Sort((a, b) => a.CustomerOrderNumber.CompareTo(b.CustomerOrderNumber));
return DbCordonelCustomerOrders != null && DbCordonelCustomerOrders.Count != 0;
}
catch (Exception)