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)