diff --git a/Common/Common.sln.DotSettings.user b/Common/Common.sln.DotSettings.user index f04ddf61..525053d6 100644 --- a/Common/Common.sln.DotSettings.user +++ b/Common/Common.sln.DotSettings.user @@ -30,6 +30,7 @@ True NewVersion True + C:\Users\Thomas Müller\AppData\Local\Temp\JetBrains\ReSharperPlatformVs17\vAny_ab6433f6\CoverageData\_Common.-1885154465\Snapshot\snapshot.utdcvr True diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisCore/GenesisMeter.cs b/Common/Hardware/WaterMeter/Genesis/GenesisCore/GenesisMeter.cs index 6e5a9917..5c0b46ae 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisCore/GenesisMeter.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisCore/GenesisMeter.cs @@ -234,6 +234,18 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore protected set; get; } + /// + public String MeterLength { + set; + get; + } = "?"; + + /// + public Boolean PressureSensorAssembled + { + protected set; get; + } + /// /// Radio frequency in MHz (433 or 868 or null). /// @@ -1423,6 +1435,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore /// /// - Frequency indicator == 0 means it is a NA-Region Octopus with EMEA FW installed. /// + /// + /// - Pressure sensor detection. + /// public void CheckRegionSizeLutCrc() { //read metrology lookup table CRC @@ -1440,6 +1455,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore LutCrc = Constants.StrUnknown; } + //read pressure sensor assembled + try + { + PressureSensorAssembled = RegisterConverter.ByteArrayToValue( + ReadRegister(Register.Metrologyasst.PressurePresent)); + } + catch (Exception)// exception will be thrown if register is not present + { + PressureSensorAssembled = false; + } + //read meter size MeterSize = MeterSizeConverter.ConvertMeterSizeEnumToSizeName( (MeterSize)RegisterConverter.ByteArrayToValue( diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisCore/IGenesisMeter.cs b/Common/Hardware/WaterMeter/Genesis/GenesisCore/IGenesisMeter.cs index ef84cf09..f5563c77 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisCore/IGenesisMeter.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisCore/IGenesisMeter.cs @@ -94,6 +94,19 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore get; } + /// + /// Length of the meter. + /// + String MeterLength { get; set; } + + /// + /// Pressure sensor assembled to meter. + /// + Boolean PressureSensorAssembled + { + get; + } + /// /// Region (EMEA, NA or China). /// diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs b/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs index 5e25bb8b..6bdf24f1 100644 --- a/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs +++ b/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs @@ -1060,8 +1060,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore continue; //TODO THW check if error should be signalized } - // ATTENTION: Take the size of the read back value as this will be filled up to a chunk of 4 - // bytes and therefore the required write value may have a smaller byte list! + // ATTENTION: The size of the writtenValue and readBackValue may deviate! var dataSize = writtenValue.Length; var strRequiredRegisterValue = ""; diff --git a/Common/Hardware/WaterMeter/Genesis/MockGenesis/MockGenesis.cs b/Common/Hardware/WaterMeter/Genesis/MockGenesis/MockGenesis.cs index f113f773..1e8e30ff 100644 --- a/Common/Hardware/WaterMeter/Genesis/MockGenesis/MockGenesis.cs +++ b/Common/Hardware/WaterMeter/Genesis/MockGenesis/MockGenesis.cs @@ -157,6 +157,24 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis get => base.MeterSize; } + /// + /// Mock object can overwrite length for test purposes + /// + public new String MeterLength + { + set => base.MeterLength = value; + get => base.MeterLength; + } + + /// + /// Mock object can overwrite pressure sensor is assembled for test purposes + /// + public new Boolean PressureSensorAssembled + { + set => base.PressureSensorAssembled = value; + get => base.PressureSensorAssembled; + } + /// /// Mock object can overwrite FwVersion for test purposes /// diff --git a/Common/Hardware/WaterMeter/Genesis/Registers/Registers.cs b/Common/Hardware/WaterMeter/Genesis/Registers/Registers.cs index a0ef6d62..706058e4 100644 --- a/Common/Hardware/WaterMeter/Genesis/Registers/Registers.cs +++ b/Common/Hardware/WaterMeter/Genesis/Registers/Registers.cs @@ -109,6 +109,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers { public static readonly String PulseEvenDistribution = "METROLOGYASST_PulseEvenDistribution"; public static readonly String PulseMode = "METROLOGYASST_PulseMode"; + public static readonly String PressurePresent = "METROLOGYASST_PressurePresent"; public static readonly String StoreConfiguration = "METROLOGYASST_StoreConfiguration"; public static readonly String FlowUnits = "METROLOGYASST_FlowUnits"; } diff --git a/Common/Hardware/WaterMeter/WaterMeterCore/WaterMeterRegisters/obj/Debug/WaterMeterRegisters.csproj.CoreCompileInputs.cache b/Common/Hardware/WaterMeter/WaterMeterCore/WaterMeterRegisters/obj/Debug/WaterMeterRegisters.csproj.CoreCompileInputs.cache index 8865d283..4163759b 100644 --- a/Common/Hardware/WaterMeter/WaterMeterCore/WaterMeterRegisters/obj/Debug/WaterMeterRegisters.csproj.CoreCompileInputs.cache +++ b/Common/Hardware/WaterMeter/WaterMeterCore/WaterMeterRegisters/obj/Debug/WaterMeterRegisters.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -89102b0142e574de38a9f47d370f3334e5e6c268 +8cb55c312de586b683d72cf58c13e2801d10e14b767777d98338d3e1473a1213 diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/Enum/PickingProcessState.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/Enum/PickingProcessState.cs deleted file mode 100644 index 894fff3a..00000000 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/Enum/PickingProcessState.cs +++ /dev/null @@ -1,73 +0,0 @@ -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum -{ - /// - /// Genesis meter final test states - /// - public enum PickingProcessState - { - /// - /// Idle (nothing to do) - /// - Idle, - - /// - /// Idle (nothing to do) - /// - ScanOrder, - /// - /// New meter detected for marker to clear all process contents like production status - /// and programming parameters. - /// - CheckNewMeter, - /// - /// Error handling - /// - Error, - /// - /// Abort final test execution - /// - Abort, - /// - /// Repeat the entire final test - /// - RepeatFailedTests, - /// - /// Final test failed - /// - PickingFailed, - /// - /// User stopped process - /// - Stop, - /// - /// Check the actual production state if all steps are executed - /// - DetectCordonel, - /// - /// Connect to Cordonel - /// - ConnectCordonel, - /// - /// Request the serial number and radio address from DB - /// - GetPickingParameters, - /// - /// Check the radio functionality - /// - CompareMeterDetails, - InstallLut, - //todo ad excisting processstates - - - - PrintReturnReport, - /// - /// Print success report - /// - PrintSuccessReport, - /// - /// Delimiter for list - /// - StateListDelimiter - } -} \ No newline at end of file diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckOrderNumber.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckOrderNumber.cs similarity index 99% rename from Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckOrderNumber.cs rename to Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckOrderNumber.cs index 3b4a7056..97b8bb64 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckOrderNumber.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckOrderNumber.cs @@ -4,7 +4,7 @@ using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; using Xylem.Common.Production.ProductionUiCordonel.Properties; using Xylem.Common.Production.ProductionUiCordonel.UserControls; -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses { public class CheckOrderNumber : BaseProductionProcess { diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckProductionState.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckProductionState.cs index 2bd5c005..3f203e66 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckProductionState.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckProductionState.cs @@ -6,8 +6,6 @@ using System.Windows; using LaaPackages.Features.Cordonel.Models; using Logic.ProductionToProductMapper.Files.Fw; using Xylem.Common.CommonCore.Consts; -using Xylem.Common.Hardware.WaterMeter.Genesis.Applications; -using Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Const; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus; @@ -16,6 +14,7 @@ using Xylem.Common.Logic.ProductionOrderCore.OrderData; using Xylem.Common.Logic.ProductionOrderCore.TestResults; using Xylem.Common.Production.ProductionUiCordonel.Model; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericModules; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses; using Xylem.Common.Production.ProductionUiCordonel.Properties; @@ -29,7 +28,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// /// Maximum of expected processing steps for this process to feed the GUI progress bar. /// - private const Int32 MaxActualProgressSteps = 22; + private const Int32 MaxActualProgressSteps = 23; /// /// Successfully test on flow test bench will return this const value. @@ -121,13 +120,13 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr ActualProcessProgress++; // Get clustered FileId of firmware package for production or on special requirement release candidates - var isSpecialActive = ProductionRequirements.IsSpecialActive != null && + var isSpecialActive = ProductionRequirements.IsSpecialActive != null && (Boolean)ProductionRequirements.IsSpecialActive && - ProductionRequirements.IsSpecialApproved != null && + ProductionRequirements.IsSpecialApproved != null && (Boolean)ProductionRequirements.IsSpecialApproved; if (string.IsNullOrEmpty(ProductionRequirements.FwVersion) || - !MeterFwUpdate.SearchProdFwInDb(ProductionRequirements.FwVersion, out var parentFileId, out error, + !MeterFwUpdate.SearchProdFwInDb(ProductionRequirements.FwVersion, out var parentFileId, out error, !isSpecialActive) || parentFileId == null) { Meter.WriteLog(error); @@ -168,9 +167,22 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr // Exit if meanwhile cancellation is required if (CancellationToken.IsCancellationRequested) return CancellationProcedure(); - + ActualProcessProgress++; + // Get the meter length from VAKO needed for radio parameter message + if (!GenericChecks.GetMeterLengthFromDb(Meter)) + { + // Meter size unknown + ErrorMsgDispatcher(Resources.StrErrorMsgMeterLengthUnknown); + return StatusReturn.Failed; + } + + // Exit if meanwhile cancellation is required + if (CancellationToken.IsCancellationRequested) + return CancellationProcedure(); + + ActualProcessProgress++; // Check if requirement will force skipping of calibration if (!ProductionRequirements.SkipCalibration) { @@ -186,7 +198,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr // Exit if meanwhile cancellation is required if (CancellationToken.IsCancellationRequested) return CancellationProcedure(); - + ActualProcessProgress++; // Get the pre- and final flow test state. @@ -202,7 +214,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr // Exit if meanwhile cancellation is required if (CancellationToken.IsCancellationRequested) return CancellationProcedure(); - + ActualProcessProgress++; // Fill the results to calibration check register restorer which will be used to read the actual @@ -251,6 +263,8 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr CalibCheckRegisterRestorer.OnProcessUpdate -= ProcessUpdate_Handler; }// Not Skip calibration loop + ActualProcessProgress++; + return StatusReturn.Okay; } @@ -315,6 +329,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// - Collect all requirement statuses before signalizing failed to summarize results starting with battery /// load. /// + /// + /// - Check radio signal levels in parameter list. + /// public override StatusReturn ExecuteProcess() { #region ----------------------------------- Check EOL Progress -------------------------------------------- @@ -404,6 +421,22 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr ActualProcessProgress++; #endregion + #region ----------------------------------- Check Kitron Radio Signal Levels ------------------------------ + + var statusReturn = CheckKitronRadioSignalLevels(out feedbackMsg); + if (StatusReturn.Failed == statusReturn) + { + ErrorMsgDispatcher(feedbackMsg); + return StatusReturn.Failed; + } + if (StatusReturn.Okay == statusReturn) + { + SuccessMsgDispatcher(feedbackMsg); + } + + ActualProcessProgress++; + #endregion + #region ----------------------------------- Check Firmware and Apps --------------------------------------- if (string.IsNullOrEmpty(CheckFwAndApps(out feedbackMsg))) @@ -506,7 +539,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr // This step may exit with "skipped" here if "special-requirement" forces to skip the check of calibration. // All following checks will be skipped as well. - var statusReturn = CheckCalibrationValues(out feedbackMsg); + statusReturn = CheckCalibrationValues(out feedbackMsg); if (StatusReturn.Skipped == statusReturn) { WarningMsgDispatcher(feedbackMsg); @@ -527,17 +560,17 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr erroneousSequenceStep = true; } #endregion -------------------------------- Check Calibration Values -------------------------------------- - + #region ----------------------------------- Summarize Check Results --------------------------------------- - + // One or more checks failed if (erroneousSequenceStep) return StatusReturn.Failed; - + // One or more checks generated a warning if (warningSequenceStep) return StatusReturn.Skipped; - + // Here everything went fine SuccessMsgDispatcher(feedbackMsg); @@ -656,11 +689,11 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr EolProgress.SpecialRequirementId = ProductionRequirements.SpecialId; EolProgress.SpecialRequirementVersion = ProductionRequirements.SpecialVersion; - feedbackMsg = isSpecialActive && - ProductionRequirements.SpecialId != null && - ProductionRequirements.SpecialVersion != null ? - Resources.StrWarningMsgSpecialRequirementActive + - $" Id.Ver: {ProductionRequirements.SpecialId}.{ProductionRequirements.SpecialVersion}" : + feedbackMsg = isSpecialActive && + ProductionRequirements.SpecialId != null && + ProductionRequirements.SpecialVersion != null ? + Resources.StrWarningMsgSpecialRequirementActive + + $" Id.Ver: {ProductionRequirements.SpecialId}.{ProductionRequirements.SpecialVersion}" : Resources.StrSuccessMsgRequirementActive + $" Id.Ver {ProductionRequirements.StandardId}.{ProductionRequirements.StandardVersion}"; @@ -855,6 +888,24 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr return EolProgress.ProductionStatusMeterSize; } + /// + /// Check the measurements from Kitron for this specific Cordonel if it is an EMEA region. + /// + /// Software Requirement Specification: + /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_008]_Check_Kitron_Radio_Levels + /// + /// + /// + /// + /// + /// - Initial. + /// + private StatusReturn CheckKitronRadioSignalLevels(out String feedbackMsg) + { + return GenericChecks.CheckKitronRadioSignalLevels(Meter, RegisterRestorer, ProductionRequirements.SkipRadioCheck, + out feedbackMsg); + } + /// /// Check the installed firmware (FW) and all individual applications (Apps) installed to the meter: /// - Take the FLEXNETVERSION as base information which FW is installed in the Cordonel and compare this with @@ -866,7 +917,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// Cordonel operational system (Breeze). /// /// Software Requirement Specification: - /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_008]_Check_FW_and_Apps + /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_009]_Check_FW_and_Apps /// /// /// @@ -874,91 +925,23 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// /// - Extracted from for better testability. /// + /// + /// - Exported to generic tests. + /// private String CheckFwAndApps(out String feedbackMsg) { - feedbackMsg = ""; - // Check installed FW version with FLEXNET information - var fwUpdate = new MeterFwUpdate(Meter); - if (EolProgress == null || - Meter == null || - ProductionRequirements == null || - string.IsNullOrEmpty(ProductionRequirements.FwVersion) || - string.IsNullOrEmpty(Meter.FwVersion) || - !Meter.FwVersion.Equals(ProductionRequirements.FwVersion) || - // Check if FW package has been loaded and contains at least the minimal required files - FwUpdatePackage == null || - FwUpdatePackage.Count < MeterFwUpdate.MinAppsRequiredForOperation) + var fwCheckMsg = GenericChecks.CheckFwAndApps(Meter, ProductionRequirements, FwUpdatePackage, + out feedbackMsg); + + // Fill the EOL progress + if (string.IsNullOrEmpty(fwCheckMsg)) { if (EolProgress != null) EolProgress.ProductionStatusFwVersion = null; - feedbackMsg += $"{Resources.StrErrorMsgRequirementFw}\n"; return ""; } - - var fileApps = new List(); - if (FwUpdatePackage != null) - { - foreach (var file in FwUpdatePackage) - { - // load the ABC (application binary container) - if (file.FileName.Contains("binfile") && - file.FileName.EndsWith(".bin") && - // Sometimes the * complete *.bin is part of the binaries containing all app in one file. - // As this is not part of the ADF it has to be skipped from loading!!!! - !file.FileName.Contains("complete")) - { - var fileApplication = new FileApplications(file.FileName) - { - BinData = new List(file.FileContent.ToList()) - }; - fileApps.Add(fileApplication); - } - // Load the ADF (application description file, containing the information - // of each application) - else if (file.FileName.Contains("product") && file.FileName.EndsWith(".txt")) - { - var enc = new System.Text.ASCIIEncoding(); - var adf = enc.GetString(file.FileContent.ToArray()); - fwUpdate.LoadPackageFileFromText(adf); - } - } - - fwUpdate.LoadFileApps(fileApps); - } - - var checkSucceeded = true; - // Compare every installed application for version and CRC with the required to be defined by the downloaded - // ABC (application binary container) - fwUpdate.CompareAllMeterAndFileApps(); - - if (// Validate package description file with required Apps (fileApps) and build the CORE REVISIONS MIN MAX - !fwUpdate.ValidateFileAppsWithPackageFile() || - // Check if any meter Apps is outdated or does contain an un-matching CRC - Meter.MeterAppListVersion.Any(app => app.Status != MeterAppState.MeterAppUpToDate && - app.Status != MeterAppState.MeterAppNotRequired)) - { - feedbackMsg += $"{Resources.StrErrorMsgAppVersionOrCrc}\n"; - checkSucceeded = false; - // Do not immediately return to summarize all errors following up - } - - // The package description file has to be parsed in advance using the fwUpdate.ValidateFileAppsWithPackageFile()!! - if (!fwUpdate.CheckCoreRevision(Meter.CoreRevision)) - { - feedbackMsg += $"{Resources.StrErrorMsgCoreRevision}\n"; - // Do not immediately return to summarize all errors following up - checkSucceeded = false; - } - - if (!checkSucceeded) - { - EolProgress.ProductionStatusFwVersion = null; - feedbackMsg += $"{Resources.StrErrorMsgRequirementFw}\n"; - return EolProgress.ProductionStatusFwVersion; - } EolProgress.ProductionStatusFwVersion = Meter.FwVersion; - feedbackMsg = $"{Resources.StrSuccessMsgRequirementFw} - Firmware: {Meter.FwVersion}"; - return EolProgress.ProductionStatusFwVersion; + return fwCheckMsg; } /// @@ -974,7 +957,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// calculation is being used. /// /// Software Requirement Specification: - /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_009]_Check_Remaining_Battery_Load + /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_010]_Check_Remaining_Battery_Load /// /// /// @@ -1075,7 +1058,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// Check the remaining lifetime /// /// Software Requirement Specification: - /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_010]_Check_Remaining_Lifetime + /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_011]_Check_Remaining_Lifetime /// /// /// @@ -1139,7 +1122,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// Check the months between first battery activation and now /// /// Software Requirement Specification: - /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_011]_Check_Storage_Months + /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_012]_Check_Storage_Months /// /// /// @@ -1215,7 +1198,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// don't match, the check of valid range and set to default values doesn't come in focus! /// /// Software Requirement Specification: - /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_012]_Check_Calibration_Values + /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_013]_Check_Calibration_Values /// /// /// @@ -1354,7 +1337,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr // Allow overwriting of calibration successfully checked to okay if (EolProgress.ProductionStatusCalibrationChecked == null) EolProgress.ProductionStatusCalibrationChecked = EOLStatus.OK; - + // Stop logging CalibCheckRegisterRestorer.OnProcessUpdate -= ProcessUpdate_Handler; @@ -1366,7 +1349,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// the according step has been successfully executed. /// /// Software Requirement Specification: - /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_013]_Check_Preadjustment + /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_014]_Check_Preadjustment /// /// /// @@ -1428,7 +1411,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// the according step has been successfully executed. /// /// Software Requirement Specification: - /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_014]_Check_Flow_Test_State + /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_015]_Check_Flow_Test_State /// /// /// diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckRadio.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckRadio.cs index d3f53451..70c8d404 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckRadio.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckRadio.cs @@ -1,12 +1,13 @@ -using System; +using LaaPackages.Features.Cordonel.Models; +using Newtonsoft.Json.Linq; +using SIRTCOM; +using System; using System.Configuration; using System.Linq; using System.Net; using System.Threading; using System.Windows.Threading; -using LaaPackages.Features.Cordonel.Models; -using Newtonsoft.Json.Linq; -using SIRTCOM; +using System.Xml.Linq; using Xylem.Common.CommonCore.Configuration; using Xylem.Common.CommonCore.Consts; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; @@ -15,6 +16,7 @@ using Xylem.Common.Logic.SoftwareAccessHelper; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; using Xylem.Common.Production.ProductionUiCordonel.Properties; using Xylem.Common.Production.ProductionUiCordonel.UserControls; +using Xylem.Common.Utils.Logging; using Button = System.Windows.Controls.Button; // ReSharper disable UnusedAutoPropertyAccessor.Local @@ -652,6 +654,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr /// /// - Optimized based on new documentations. /// + /// + /// - Logging path changed. + /// private void SendPamListenSemi(Int32 radioAddress, Int32 byteComPort, String strKey) { if (_dataContainer == null || _stateMachine == null) @@ -665,9 +670,27 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr _dataContainer.RadioAdress = radioAddress; _stateMachine.initialise((Byte)byteComPort); - var date = DateTime.Now.Date; - var loggingPath = $"C:\\GenesisLog\\{date:yyyy-MM-dd}\\ProductionUiCordonel\\{Meter.PcbId}_RadioCheck.log"; - _stateMachine.StartLoggin(loggingPath); + + try + { + var path = NLogHelper.GetApplicationDataPath(); + if (string.IsNullOrEmpty(path)) + { + path = NLogHelper.GetCurrentApplicationFolder(); + } + + var a = XElement.Load(path); + var baseLoggingPath = a.Elements().First(s => s.Name.LocalName == "variable").Attributes() + .First(s => s.Value == "BasePath").NextAttribute.Value; + + var loggingPath = + $"{baseLoggingPath}\\{DateTime.Now:yyyy-MM-dd}\\ProductionUiCordonel\\{Meter.PcbId}_RadioCheck.log"; + _stateMachine.StartLoggin(loggingPath); + } + catch (Exception) + { + // ignore + } LogNewStatusMsg($"{Resources.StrRadioMsgSendPam}: {radioAddress.ToString()}"); diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckSerialNumber.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckSerialNumber.cs similarity index 99% rename from Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckSerialNumber.cs rename to Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckSerialNumber.cs index ba488770..b3f87824 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckSerialNumber.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckSerialNumber.cs @@ -4,7 +4,7 @@ using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; using Xylem.Common.Production.ProductionUiCordonel.Properties; using Xylem.Common.Production.ProductionUiCordonel.UserControls; -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses { public class CheckSerialNumber : BaseProductionProcess { diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessStatesDef.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessStatesDef.cs index 65fc798a..da4b4f3e 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessStatesDef.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessStatesDef.cs @@ -151,25 +151,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr // Kick off parallel process execution kickOffParallelState: ProcessState.GetProgrammingParameters), - // This scans the order number, it has to be executed exclusively with automatic - new ProcessStateStruct( - productionProcess: new CheckOrderNumber(Resources.StrStateCheckOrderNumber), - processState: ProcessState.CheckOrderNumber, - processInfo: Resources.StrStateCheckOrderNumber, - productionProcessNo: 11, - nextStateOnSuccess: ProcessState.CheckSerialNumber), - - // This scans the serial number, it has to be executed exclusively with automatic - new ProcessStateStruct( - productionProcess: new CheckSerialNumber( Resources.StrStateCheckSerialNumber), - processState: ProcessState.CheckSerialNumber, - processInfo: Resources.StrStateCheckSerialNumber, - productionProcessNo: 12, - nextStateOnSuccess: ProcessState.CheckAttachments), - - #endregion -------------------------------- GENERIC-STATES -------------------------------------------- - - #region ----------------------------------- EOL-STATES ------------------------------------------------ // Precondition: - The connection process has to be completed as a readout of some register // values from the Cordonel are needed to check the update capability: // - Wait on completed connection process before starting this process. @@ -186,6 +167,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr // Wait until this process has been successfully completed waitForSingleProcess: ProcessState.ConnectCordonel), + #endregion -------------------------------- GENERIC-STATES -------------------------------------------- + + #region ----------------------------------- EOL-STATES ------------------------------------------------ // Precondition: - The connection process has to be completed as a readout of some register // values from the Cordonel are needed to check the update capability: // - Wait on completed connection process before starting this process. @@ -201,7 +185,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr kickOffParallelState: ProcessState.ProcessPasswordFile, // Wait until this process has been successfully completed waitForSingleProcess: ProcessState.ConnectCordonel), - // Precondition: - The connection process has to be completed as a password change in the DB // will take place: Skeleton to Password Level 8. Not waiting for completion may cause side @@ -265,6 +248,22 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr productionProcessNo: 10, nextStateOnSuccess: ProcessState.CheckOrderNumber), + // This scans the order number, it has to be executed exclusively with automatic + new ProcessStateStruct( + productionProcess: new CheckOrderNumber(Resources.StrStateCheckOrderNumber), + processState: ProcessState.CheckOrderNumber, + processInfo: Resources.StrStateCheckOrderNumber, + productionProcessNo: 11, + nextStateOnSuccess: ProcessState.CheckSerialNumber), + + // This scans the serial number, it has to be executed exclusively with automatic + new ProcessStateStruct( + productionProcess: new CheckSerialNumber( Resources.StrStateCheckSerialNumber), + processState: ProcessState.CheckSerialNumber, + processInfo: Resources.StrStateCheckSerialNumber, + productionProcessNo: 12, + nextStateOnSuccess: ProcessState.CheckAttachments), + // Precondition: - All checks have to be executed with positive result new ProcessStateStruct( productionProcess: new CheckAttachments(Resources.StrStateCheckAttachments), diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/ExecFinalParametrization.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/ExecFinalParametrization.cs index b17d558d..cc882cba 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/ExecFinalParametrization.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/ExecFinalParametrization.cs @@ -3,6 +3,7 @@ using System.Linq; using LaaPackages.Features.Cordonel.Models; using Xylem.Common.CommonCore.Consts; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses; using Xylem.Common.Production.ProductionUiCordonel.Properties; namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericModules/GenericChecks.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericModules/GenericChecks.cs new file mode 100644 index 00000000..37a1a667 --- /dev/null +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericModules/GenericChecks.cs @@ -0,0 +1,205 @@ +using LaaPackages.Features.Cordonel.Models; +using Logic.ProductionToProductMapper.Files.Fw; +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.Applications; +using Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Const; +using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; +using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile; +using Xylem.Common.Logic.ProductionOrderCore.Vako; +using Xylem.Common.Logic.SoftwareAccessHelper; +using Xylem.Common.Production.ProductionUiCordonel.Properties; + +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericModules +{ + internal static class GenericChecks + { + /// + /// Check the measurements from Kitron for this specific Cordonel if it is an EMEA region. + /// + /// + /// + /// + /// + /// + /// + /// - Initial. + /// + /// + /// - Import from CheckProductionState for common use. + /// + public static StatusReturn CheckKitronRadioSignalLevels(IGenesisMeter meter, RegisterRestorer registerRestorer, + Boolean skipRadioCheck, out String feedbackMsg) + { + feedbackMsg = ""; + if (meter == null || + string.IsNullOrEmpty(meter.MeterSize) || + string.IsNullOrEmpty(meter.Region)) + { + return StatusReturn.Failed; + } + + // The NA region has no radio or radio check should be ignored + if (meter.Region.Equals("NA") || skipRadioCheck) + { + return StatusReturn.Skipped; + } + var pressureSensorAssembled = + meter.PressureSensorAssembled ? $", {Resources.StrLblPressureSensorAssembledTxt}" : ""; + var meterInfo = $"{Resources.StrLblRadioFrequencyTxt}: {meter.RadioFrequencyMhz} MHz," + + $"{Resources.StrLblMeterSizeTxt}: {meter.MeterSize}, " + + $"{Resources.StrLblMeterLengthTxt}: {meter.MeterLength} mm" + + $"{pressureSensorAssembled}"; + // On unknown radio signal level parameters from Kitron those are not in the list of the programming parameters + if (!registerRestorer.RecoveryRegisters.Any(x => x.RegisterIdent.Equals("SENSUSRADIO_PowerLevel"))) + { + feedbackMsg = Resources.StrErrorMsgRadioSignalLevels + " " + meterInfo; + return StatusReturn.Failed; + } + + feedbackMsg = Resources.StrSuccessMsgRadioSignalLevels + ". " + meterInfo; + return StatusReturn.Okay; + } + + /// + /// Check the installed firmware (FW) and all individual applications (Apps) installed to the meter: + /// - Take the FLEXNETVERSION as base information which FW is installed in the Cordonel and compare this with + /// the production-requirement, + /// - The downloaded FW package containing all Apps as application-binary-container (ABC) will be compared with + /// the reported Apps by the Cordonel for their version and CRC using the " class, + /// - Crosscheck if the application-description-file (ADF) states all Apps which are installed in the Cordonel, + /// - Check the Core-Revision of the Cordonel against the ADF to guarantee that this FW is supported by the + /// Cordonel operational system (Breeze). + /// + /// + /// + /// + /// + /// + /// + /// - Initial. + /// + /// + /// - Import from CheckProductionState for common use. + /// + public static String CheckFwAndApps(IGenesisMeter meter, CordonelRequirements requirements, + List fwUpdatePackage, out String feedbackMsg) + { + feedbackMsg = ""; + // Check installed FW version with FLEXNET information + var fwUpdate = new MeterFwUpdate(meter); + if (meter == null || + requirements == null || + string.IsNullOrEmpty(requirements.FwVersion) || + string.IsNullOrEmpty(meter.FwVersion) || + !meter.FwVersion.Equals(requirements.FwVersion) || + // Check if FW package has been loaded and contains at least the minimal required files + fwUpdatePackage == null || + fwUpdatePackage.Count < MeterFwUpdate.MinAppsRequiredForOperation) + { + feedbackMsg += $"{Resources.StrErrorMsgRequirementFw}\n"; + return ""; + } + + var fileApps = new List(); + foreach (var file in fwUpdatePackage) + { + // load the ABC (application binary container) + if (file.FileName.Contains("binfile") && + file.FileName.EndsWith(".bin") && + // Sometimes the * complete *.bin is part of the binaries containing all app in one file. + // As this is not part of the ADF it has to be skipped from loading!!!! + !file.FileName.Contains("complete")) + { + var fileApplication = new FileApplications(file.FileName) + { + BinData = new List(file.FileContent.ToList()) + }; + fileApps.Add(fileApplication); + } + // Load the ADF (application description file, containing the information + // of each application) + else if (file.FileName.Contains("product") && file.FileName.EndsWith(".txt")) + { + var enc = new System.Text.ASCIIEncoding(); + var adf = enc.GetString(file.FileContent.ToArray()); + fwUpdate.LoadPackageFileFromText(adf); + } + } + + fwUpdate.LoadFileApps(fileApps); + + var checkSucceeded = true; + // Compare every installed application for version and CRC with the required to be defined by the downloaded + // ABC (application binary container) + fwUpdate.CompareAllMeterAndFileApps(); + + if ( // Validate package description file with required Apps (fileApps) and build the CORE REVISIONS MIN MAX + !fwUpdate.ValidateFileAppsWithPackageFile() || + // Check if any meter Apps is outdated or does contain an un-matching CRC + meter.MeterAppListVersion.Any(app => app.Status != MeterAppState.MeterAppUpToDate && + app.Status != MeterAppState.MeterAppNotRequired)) + { + feedbackMsg += $"{Resources.StrErrorMsgAppVersionOrCrc}\n"; + checkSucceeded = false; + // Do not immediately return to summarize all errors following up + } + + // The package description file has to be parsed in advance using the fwUpdate.ValidateFileAppsWithPackageFile()!! + if (!fwUpdate.CheckCoreRevision(meter.CoreRevision)) + { + feedbackMsg += $"{Resources.StrErrorMsgCoreRevision}\n"; + // Do not immediately return to summarize all errors following up + checkSucceeded = false; + } + + if (!checkSucceeded) + { + feedbackMsg += $"{Resources.StrErrorMsgRequirementFw}\n"; + return ""; + } + + feedbackMsg = $"{Resources.StrSuccessMsgRequirementFw} - Firmware: {meter.FwVersion}"; + return meter.FwVersion; + } + + /// + /// Get the meter length form database as single VAKO parameter + /// + /// + /// + /// + /// - Initial. + /// + public static Boolean GetMeterLengthFromDb(IGenesisMeter meter) + { + if (meter == null) + return false; + try + { + var a = LocalWebRequest.GetRequest( + $"{ServiceUrls.GenesisFinalCheckServiceUrl()}GetSingleVakoKey?ProductionOrderNumber=" + + $"{meter.OrderNumber}&KeyName=C_GEN_BAULAENGE"); + var response = JsonConvert.DeserializeObject(a); + + if (response == null || string.IsNullOrEmpty(response.Value)) + { + // Meter size unknown + return false; + } + + meter.MeterLength = response.Value; + return true; + } + catch (Exception) + { + // Meter size unknown + return false; + } + } + } +} diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/GetFinalParametrization.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/GetFinalParametrization.cs similarity index 99% rename from Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/GetFinalParametrization.cs rename to Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/GetFinalParametrization.cs index e08cafe3..aeb4c482 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/GetFinalParametrization.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/GetFinalParametrization.cs @@ -7,10 +7,10 @@ using Xylem.Common.CommonCore.Consts; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; using Xylem.Common.Logic.SoftwareAccessHelper; -using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses; using Xylem.Common.Production.ProductionUiCordonel.Properties; -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses { /// /// Request for parameters for final programming including VAKO and CSD diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/CheckOrderNumber.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/CheckOrderNumber.cs new file mode 100644 index 00000000..7fc4b88f --- /dev/null +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/CheckOrderNumber.cs @@ -0,0 +1,96 @@ +using System; +using Xylem.Common.CommonCore.Consts; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; +using Xylem.Common.Production.ProductionUiCordonel.Properties; +using Xylem.Common.Production.ProductionUiCordonel.UserControls; + +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.PickingProcesses +{ + public class CheckOrderNumber : BaseProductionProcess + { + // string from scanner with string delimiter + private String _scan = ""; + // marker for scan input received + private Boolean _scanInputReceived; + /// + /// Ctor + /// + public CheckOrderNumber(String name) : base( name) + { + } + + /// + protected override void InitUserControl() + { + UserControl = new UcBarcodeInput + { + lblHeadLine = { Content = Resources.StrInstructionScanOrder }, + tbxScan = { Text = "" } + }; + } + + /// + /// Event handler taking the input from text box which should be scanned but also can be input manually. + /// + /// + /// + /// - Initial + /// + private void UserControlInput_Handler(Object sender, String input) + { + _scan = input; + _scanInputReceived = true; + } + + /// + /// Scanning of order number from production order sheet and comparing with DB. + /// + /// + /// + /// - Initial + /// + /// + /// - Removed signals for and as + /// these will be automatically set based on return value in + /// . + /// + public override StatusReturn ExecuteProcess() + { + if (Meter == null) + { + return StatusReturn.Failed; + } + + SignalRunningState(); + + if (UserControl == null) + { + ErrorMsgDispatcher(Resources.StrErrorMsgScanOrderNumber); + return StatusReturn.Failed; + } + + var ucBarCode = (UcBarcodeInput)UserControl; + ucBarCode.OnBarcodeInput += UserControlInput_Handler; + + // set focus to text input for scanner + ucBarCode.FocusMe(); + _scanInputReceived = false; + + // wait for new line + while (!_scanInputReceived) + { + } + + ucBarCode.OnBarcodeInput -= UserControlInput_Handler; + + if (!string.IsNullOrEmpty(_scan) && _scan.Length > 5) + { + //TODO Roland, Do something with the scanned order + return StatusReturn.Okay; + } + + ErrorMsgDispatcher(Resources.StrErrorMsgScanOrderNumber); + return StatusReturn.Failed; + } + } +} diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/CheckProductionState.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/CheckProductionState.cs index 1da6479e..7e4efa18 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/CheckProductionState.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/CheckProductionState.cs @@ -1,15 +1,13 @@ -using System; +using Logic.ProductionToProductMapper.Files.Fw; +using System; using System.Collections.Generic; -using System.Linq; using System.Windows; -using Logic.ProductionToProductMapper.Files.Fw; using Xylem.Common.CommonCore.Consts; -using Xylem.Common.Hardware.WaterMeter.Genesis.Applications; -using Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Const; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus; using Xylem.Common.Logic.ProductionOrderCore.OrderData; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericModules; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses; using Xylem.Common.Production.ProductionUiCordonel.Properties; @@ -23,7 +21,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki /// /// Maximum of expected processing steps for this process to feed the GUI progress bar. /// - private const Int32 MaxActualProgressSteps = 13; + private const Int32 MaxActualProgressSteps = 14; /// /// FW update package containing the ABC and the ADF. @@ -124,6 +122,15 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki ActualProcessProgress++; + // Get the meter length from VAKO needed for radio parameter message + if (!GenericChecks.GetMeterLengthFromDb(Meter)) + { + // Meter size unknown + ErrorMsgDispatcher(Resources.StrErrorMsgMeterLengthUnknown); + return StatusReturn.Failed; + } + ActualProcessProgress++; + return StatusReturn.Okay; } @@ -229,6 +236,22 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki ActualProcessProgress++; #endregion + #region ----------------------------------- Check Kitron Radio Signal Levels ------------------------------ + + statusReturn = CheckKitronRadioSignalLevels(out feedbackMsg); + if (StatusReturn.Failed == statusReturn) + { + ErrorMsgDispatcher(feedbackMsg); + return StatusReturn.Failed; + } + if (StatusReturn.Okay == statusReturn) + { + SuccessMsgDispatcher(feedbackMsg); + } + + ActualProcessProgress++; + #endregion + #region ----------------------------------- Check Firmware and Apps --------------------------------------- if (string.IsNullOrEmpty(CheckFwAndApps(out feedbackMsg))) @@ -531,6 +554,25 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki return ProductionRequirements.MeterSize; } + /// + /// Check the measurements from Kitron for this specific Cordonel if it is an EMEA region. + /// + /// Software Requirement Specification: + /// [SRS_TBF_EOL_PP_CHECK_PROD_STATE_007]_Check_Kitron_Radio_Levels + /// + /// + /// + /// + /// + /// - Initial. + /// + private StatusReturn CheckKitronRadioSignalLevels(out String feedbackMsg) + { + return GenericChecks.CheckKitronRadioSignalLevels(Meter, RegisterRestorer, ProductionRequirements.SkipRadioCheck, + out feedbackMsg); + } + + /// /// Check the installed firmware (FW) and all individual applications (Apps) installed to the meter: /// - Take the FLEXNETVERSION as base information which FW is installed in the Cordonel and compare this with @@ -542,7 +584,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki /// Cordonel operational system (Breeze). /// /// Software Requirement Specification: - /// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_007]_Check_FW_and_Apps + /// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_008]_Check_FW_and_Apps /// /// /// @@ -550,86 +592,12 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki /// /// - Initial. /// + /// + /// - Exported to generic tests. + /// private String CheckFwAndApps(out String feedbackMsg) { - feedbackMsg = ""; - // Check installed FW version with FLEXNET information - var fwUpdate = new MeterFwUpdate(Meter); - if (Meter == null || - ProductionRequirements == null || - string.IsNullOrEmpty(ProductionRequirements.FwVersion) || - string.IsNullOrEmpty(Meter.FwVersion) || - !Meter.FwVersion.Equals(ProductionRequirements.FwVersion) || - // Check if FW package has been loaded and contains at least the minimal required files - FwUpdatePackage == null || - FwUpdatePackage.Count < MeterFwUpdate.MinAppsRequiredForOperation) - { - feedbackMsg += $"{Resources.StrErrorMsgRequirementFw}\n"; - return ""; - } - - var fileApps = new List(); - if (FwUpdatePackage != null) - { - foreach (var file in FwUpdatePackage) - { - // load the ABC (application binary container) - if (file.FileName.Contains("binfile") && - file.FileName.EndsWith(".bin") && - // Sometimes the * complete *.bin is part of the binaries containing all app in one file. - // As this is not part of the ADF it has to be skipped from loading!!!! - !file.FileName.Contains("complete")) - { - var fileApplication = new FileApplications(file.FileName) - { - BinData = new List(file.FileContent.ToList()) - }; - fileApps.Add(fileApplication); - } - // Load the ADF (application description file, containing the information - // of each application) - else if (file.FileName.Contains("product") && file.FileName.EndsWith(".txt")) - { - var enc = new System.Text.ASCIIEncoding(); - var adf = enc.GetString(file.FileContent.ToArray()); - fwUpdate.LoadPackageFileFromText(adf); - } - } - - fwUpdate.LoadFileApps(fileApps); - } - - var checkSucceeded = true; - // Compare every installed application for version and CRC with the required to be defined by the downloaded - // ABC (application binary container) - fwUpdate.CompareAllMeterAndFileApps(); - - if (// Validate package description file with required Apps (fileApps) and build the CORE REVISIONS MIN MAX - !fwUpdate.ValidateFileAppsWithPackageFile() || - // Check if any meter Apps is outdated or does contain an un-matching CRC - Meter.MeterAppListVersion.Any(app => app.Status != MeterAppState.MeterAppUpToDate && - app.Status != MeterAppState.MeterAppNotRequired)) - { - feedbackMsg += $"{Resources.StrErrorMsgAppVersionOrCrc}\n"; - checkSucceeded = false; - // Do not immediately return to summarize all errors following up - } - - // The package description file has to be parsed in advance using the fwUpdate.ValidateFileAppsWithPackageFile()!! - if (!fwUpdate.CheckCoreRevision(Meter.CoreRevision)) - { - feedbackMsg += $"{Resources.StrErrorMsgCoreRevision}\n"; - // Do not immediately return to summarize all errors following up - checkSucceeded = false; - } - - if (!checkSucceeded) - { - feedbackMsg += $"{Resources.StrErrorMsgRequirementFw}\n"; - return ""; - } - feedbackMsg = $"{Resources.StrSuccessMsgRequirementFw} - Firmware: {Meter.FwVersion}"; - return Meter.FwVersion; + return GenericChecks.CheckFwAndApps(Meter, ProductionRequirements, FwUpdatePackage, out feedbackMsg); } /// @@ -645,7 +613,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki /// calculation is being used. /// /// Software Requirement Specification: - /// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_008]_Check_Remaining_Battery_Load + /// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_009]_Check_Remaining_Battery_Load /// /// /// @@ -734,7 +702,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki /// Check the remaining lifetime /// /// Software Requirement Specification: - /// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_009]_Check_Remaining_Lifetime + /// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_010]_Check_Remaining_Lifetime /// /// /// @@ -785,7 +753,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki /// Check the months between first battery activation and now /// /// Software Requirement Specification: - /// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_010]_Check_Storage_Months + /// [SRS_TBF_PICK_PP_CHECK_PROD_STATE_011]_Check_Storage_Months /// /// /// diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/PickingProcessStatesDef.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/PickingProcessStatesDef.cs index 2e124893..c75993b3 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/PickingProcessStatesDef.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/PickingProcesses/PickingProcessStatesDef.cs @@ -146,20 +146,33 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki processState: ProcessState.GetSerialNumberAndRadioAddress, processInfo: Resources.StrStateGetSerialAndRadioAddress, productionProcessNo: 2, - nextStateOnSuccess: ProcessState.CheckOrderNumber, - waitForAllProcesses: true), - + // Avoid automatic change after completion as parallel process is active + nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion, + // Kick off parallel process execution + kickOffParallelState: ProcessState.GetProgrammingParameters), + + // Precondition: - The connection process has to be completed as a readout of some register + // values from the Cordonel are needed to check the update capability: + // - Wait on completed connection process before starting this process. + new ProcessStateStruct( + productionProcess: new GetFinalParametrization(Resources.StrStateGetProgrammingParameters), + processState: ProcessState.GetProgrammingParameters, + processInfo: Resources.StrStateGetProgrammingParameters, + productionProcessNo: 3, + nextStateOnSuccess: ProcessState.CheckOrderNumber, + // Wait until this process has been successfully completed + waitForSingleProcess: ProcessState.ConnectCordonel), + #endregion -------------------------------- GENERIC-STATES -------------------------------------------- + + #region ----------------------------------- PICKING-STATES -------------------------------------------- // This scans the order number, it has to be executed exclusively with automatic new ProcessStateStruct( productionProcess: new CheckOrderNumber(Resources.StrStateCheckOrderNumber), processState: ProcessState.CheckOrderNumber, processInfo: Resources.StrStateCheckOrderNumber, - productionProcessNo: 3, + productionProcessNo: 4, nextStateOnSuccess: ProcessState.CheckProductionState), - #endregion -------------------------------- GENERIC-STATES -------------------------------------------- - - #region ----------------------------------- PICKING-STATES -------------------------------------------- // Precondition: - The connection process has to be completed as a readout of some register // values from the Cordonel are needed to check the update capability: // - Wait on completed connection process before starting this process. @@ -167,7 +180,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Picki productionProcess: new CheckProductionState(Resources.StrStateCheckProductionState), processState: ProcessState.CheckProductionState, processInfo: Resources.StrStateCheckProductionState, - productionProcessNo: 4, + productionProcessNo: 5, nextStateOnSuccess: ProcessState.Idle), //TODO Roland: implement your states here diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/ProcessController.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/ProcessController.cs index a416f514..317a2679 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/ProcessController.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/ProcessController.cs @@ -653,7 +653,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses /// /// - Feed with processStateStruct. /// - protected void StartProcess(ProcessStateStruct processStateStruct) + private void StartProcess(ProcessStateStruct processStateStruct) { // deny access if uninitialized if (Processes == null || processStateStruct.ProductionProcess == null) diff --git a/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj b/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj index 4ab773c3..2bfd1c05 100644 --- a/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj +++ b/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj @@ -259,6 +259,7 @@ 4.0 + @@ -284,8 +285,8 @@ ctlMultiModePressure.xaml - + @@ -299,6 +300,7 @@ + @@ -312,12 +314,12 @@ - - + + - + diff --git a/Common/Production/ProductionUiCordonel/ProductionWindow.xaml b/Common/Production/ProductionUiCordonel/ProductionWindow.xaml index fe88c0f9..ddf06466 100644 --- a/Common/Production/ProductionUiCordonel/ProductionWindow.xaml +++ b/Common/Production/ProductionUiCordonel/ProductionWindow.xaml @@ -112,6 +112,7 @@