diff --git a/Common/Common.sln b/Common/Common.sln
index 05500228..17747b42 100644
--- a/Common/Common.sln
+++ b/Common/Common.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.33423.255
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36121.58 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{7A0EE7B8-6B7E-41E9-B679-319C8CA48CF1}"
EndProject
@@ -346,7 +346,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LaaPackages.Features.Cordon
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LaaPackages.Extensions", "LaaPackages\LaaPackages.Extensions\LaaPackages.Extensions.csproj", "{15A06398-ECB6-49C9-ACB4-52A495A886A6}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LaaProductionWeb.Resources", "LaaPackages\LaaProductionWeb.Resources\LaaProductionWeb.Resources.csproj", "{DA65E376-3D35-4D96-913A-7197FCA6DF48}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LaaProductionWeb.Resources", "LaaPackages\LaaProductionWeb.Resources\LaaProductionWeb.Resources.csproj", "{9E070488-15DE-418A-8606-5B79056C6E9F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserAccessCtrl", "Utils\UserAccessCtrl\UserAccessCtrl.csproj", "{2D55BBD1-5373-484C-8781-C6ECEAFC2A90}"
EndProject
@@ -365,9 +365,6 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonConsole", "CommonConsole\CommonConsole.csproj", "{AFC428F5-0141-4A3F-BEF2-470A89D972F6}"
EndProject
Global
- GlobalSection(SharedMSBuildProjectFiles) = preSolution
- Utils\DateTimeServerShared\DateTimeServerShared.projitems*{4806d89a-fbfb-41bc-aaa7-2242444bf55a}*SharedItemsImports = 4
- EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
_MANUAL_CONTROL|Any CPU = _MANUAL_CONTROL|Any CPU
_MANUAL_CONTROL|Mixed Platforms = _MANUAL_CONTROL|Mixed Platforms
@@ -5326,70 +5323,70 @@ Global
{15A06398-ECB6-49C9-ACB4-52A495A886A6}.XP32bit|x64.Build.0 = Release|Any CPU
{15A06398-ECB6-49C9-ACB4-52A495A886A6}.XP32bit|x86.ActiveCfg = Release|Any CPU
{15A06398-ECB6-49C9-ACB4-52A495A886A6}.XP32bit|x86.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.COM|Any CPU.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.COM|Any CPU.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.COM|Mixed Platforms.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.COM|x64.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.COM|x64.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.COM|x86.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.COM|x86.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Debug|x64.ActiveCfg = Debug|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Debug|x64.Build.0 = Debug|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Debug|x86.ActiveCfg = Debug|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Debug|x86.Build.0 = Debug|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.PerformTest|Any CPU.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.PerformTest|x64.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.PerformTest|x64.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.PerformTest|x86.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.PerformTest|x86.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Release|Any CPU.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Release|x64.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Release|x64.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Release|x86.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.Release|x86.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.ReleaseTest|x64.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.ReleaseTest|x86.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.XP32bit|Any CPU.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.XP32bit|x64.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.XP32bit|x64.Build.0 = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.XP32bit|x86.ActiveCfg = Release|Any CPU
- {DA65E376-3D35-4D96-913A-7197FCA6DF48}.XP32bit|x86.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.COM|Any CPU.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.COM|Any CPU.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.COM|Mixed Platforms.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.COM|x64.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.COM|x64.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.COM|x86.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.COM|x86.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Debug|x64.Build.0 = Debug|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Debug|x86.Build.0 = Debug|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.PerformTest|Any CPU.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.PerformTest|x64.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.PerformTest|x64.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.PerformTest|x86.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.PerformTest|x86.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Release|x64.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Release|x64.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Release|x86.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.Release|x86.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.ReleaseTest|x64.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.ReleaseTest|x86.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.XP32bit|Any CPU.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.XP32bit|x64.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.XP32bit|x64.Build.0 = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.XP32bit|x86.ActiveCfg = Release|Any CPU
+ {9E070488-15DE-418A-8606-5B79056C6E9F}.XP32bit|x86.Build.0 = Release|Any CPU
{2D55BBD1-5373-484C-8781-C6ECEAFC2A90}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{2D55BBD1-5373-484C-8781-C6ECEAFC2A90}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{2D55BBD1-5373-484C-8781-C6ECEAFC2A90}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
@@ -5914,7 +5911,7 @@ Global
{F69A79FA-548D-4E21-887E-01FABDAD9E73} = {696A94BE-7237-4AE2-9E36-6059DE519971}
{8BEFD3AC-BB21-4B62-8D9A-CF8CBFD439EB} = {2E31C385-4FFC-473E-9C00-D7DC48140704}
{15A06398-ECB6-49C9-ACB4-52A495A886A6} = {2E31C385-4FFC-473E-9C00-D7DC48140704}
- {DA65E376-3D35-4D96-913A-7197FCA6DF48} = {2E31C385-4FFC-473E-9C00-D7DC48140704}
+ {9E070488-15DE-418A-8606-5B79056C6E9F} = {2E31C385-4FFC-473E-9C00-D7DC48140704}
{2D55BBD1-5373-484C-8781-C6ECEAFC2A90} = {7A0EE7B8-6B7E-41E9-B679-319C8CA48CF1}
{30BF7357-0B6C-498D-8123-5AACC66B3E5F} = {7A0EE7B8-6B7E-41E9-B679-319C8CA48CF1}
{4928FC37-15EC-4872-8514-EA4ADCC4139D} = {AE29BDE3-843C-4B9B-8B02-D3C4814028AC}
@@ -5926,6 +5923,9 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4BCB7B69-696C-436A-86F7-C91EA5588164}
EndGlobalSection
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ Utils\DateTimeServerShared\DateTimeServerShared.projitems*{4806d89a-fbfb-41bc-aaa7-2242444bf55a}*SharedItemsImports = 4
+ EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs.bak b/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs.bak
deleted file mode 100644
index 5a31d27f..00000000
--- a/Common/Hardware/WaterMeter/Genesis/GenesisCore/RegisterRestorer.cs.bak
+++ /dev/null
@@ -1,1516 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-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
-{
- ///
- /// Read, compare and restore if unequal al registers marked with
- /// equals
- /// ".
- /// The reader will use the byte values as they are unmodified and
- /// will not be rounded and therefor possibly fail the comparison.
- /// For logging the register value will be converted its unit.
- ///
- public class RegisterRestorer : IProcessState
- {
- ///
- /// PCB ID for pre update read for comparison
- ///
- private String _pcbIdInitialRegisterRead = Constants.StrUnknown;
-
- ///
- /// PCB ID for pre update write for comparison
- ///
- private String _pcbIdWriteRegisters;
-
- ///
- /// PCB ID for post update for comparison
- ///
- private String _pcbIdFinalRegisterRead = Constants.StrUnknown;
-
- ///
- /// Collection of recovery registers and values
- ///
- public List RecoveryRegisters;
-
- ///
- /// Register content on initial connect to keep those during update
- ///
- private List _initialRegisters = new List();
-
- ///
- /// Register content after all operation had been performed
- ///
- private List _finalRegisters = new List();
-
- ///
- /// Register which shall be restored after change of FW or after register recovery
- ///
- public Int32 RecoveryRegisterCount => RecoveryRegisters.Count;
-
- ///
- /// Register access event for message dispatcher to caller
- ///
- public event EventHandler OnProcessUpdate;
-
- ///
- /// List for un-reversed parameters which can be written, all others need to be swapped byte-wise
- ///
- private static readonly List _unReversedParameters = new List
- {
- "SENSUSRADIO_Authentification", //UInt96
- "SENSUSRADIO_EncryptionKey", //UInt128
- "SENSUSRADIO_TfxSecondaryChannelInfo_1", //UInt48
- "SENSUSRADIO_TfxSecondaryChannelInfo_2", //UInt48
- "SENSUSRADIO_CustomerText", //UInt72
- "SENSUSRADIO_Tfx_Structure", //UInt88
- "GENESISFLOW_DisplayPow10", //SInt8
- "METROLOGYASST_FlowPoint", //Enum8
- "CUSTOMER_SerialNumber", //String
- "SYSTEM_CustomerSerialNumber0", //String
- "SYSTEM_CustomerSerialNumber1", //String
- "SYSTEM_CustomerSerialNumber2", //String
- "SYSTEM_CustomerSerialNumber3", //String
- "TESTMANAGER_OutputFile" //String
- };
-
- ///
- /// Registers manually explicit excluded from comparison as those may change even if those have the
- /// "StaticType": "static" in the configuration.json but will change for some reason.
- ///
- private static readonly List _excludedFromCompareParameters = new List
- {
- "CUSTOMER_AlarmVisualMask", // Fully hard coded, cannot be overwritten
- "CUSTOMER_AlarmEnableMask", // Will be overwritten by SENSUSRADIO if set System state to 0xFF
- "CUSTOMER_AppArrangement", // Is read only, makes no sense to compare anything
- "SENSUSRADIO_UpgFWVersion" // After a FW-Update the FW version has changed
- };
-
- ///
- /// Registers manually explicit excluded from reading as those do not contain useful information.
- /// Applies for RW commands not RPC data type.
- ///
- private static readonly List _excludedFromReadParameters = new List
- {
- "CUSTOMER_InternalLoginTest", // Does NOT respond
- "CUSTOMER_AlarmVisualAutoClearMask", // Does NOT respond
- "SYSTEM_CRC", // Needs application number written to it
- "SYSTEM_CRC32", // Needs application number written to it
- "SYSTEM_ExitReason", // Needs application number written to it
- "SYSTEM_DriveCapacity", // Needs drive number written to it
- "GENESISFLOW_TriggerActive", // Does NOT respond
- "SENSUSRADIO_CurrentLoopMax", // Does NOT respond
- "SENSUSRADIO_CurrentLoopSource", // Does NOT respond
- "SENSUSRADIO_CustomerText", // Does NOT respond
- "SENSUSRADIO_TfxSecondaryChannelInfo_1",// Does NOT respond
- "SENSUSRADIO_TfxSecondaryChannelInfo_2" // Does NOT respond
- };
-
- ///
- /// Pre-programming parameters for all devices defined here, will be filled with radio parameters
- /// if meter has radio
- ///
- private static readonly List _prepareProgramming = new List
- {
- // The display needs to be unsealed for change of unit and resolution
- new RecoveryRegisterItem("GENESISFLOW_SealDisplay", new Byte[] { 0x00 })
- };
-
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- private readonly List _failedComparisonRegisters = new List();
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- private List _dbParameterRegisterList = new List();
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- private List _initialRegisterList = new List();
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- private List _finalRegisterList = new List();
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- private readonly List _readableRegisterList = new List();
-
- ///
- /// Post programming parameters for all devices
- ///
- private static readonly List _finalizeProgrammingAll = new List
- {
- new RecoveryRegisterItem("LOGGER_TriggerLogFlush", new Byte[] { 0x01 }),
- // set counter to 0 as this is a value how often the radio detected a reset
- new RecoveryRegisterItem("PERIODICLOG_ResetCounter", new Byte[] { 0x00 }),
- // trigger idle 0 releases the display to normal operation
- new RecoveryRegisterItem("GENESISFLOW_TriggerIdle", new Byte[] { 0x00 })
- };
-
- ///
- /// Post programming parameters for EMEA region as NA region doesn't have radio and seal display shouldn't
- /// be executed.
- ///
- private static readonly List _finalizeProgrammingEmea = new List
- {
- // System state 0xFF will force a storage of all parameters and reset, followed by system state 0x02
- // for customer mode, the reset needs only a few milliseconds
- // Attention logout-delay-login required after this step!
- new RecoveryRegisterItem("SENSUSRADIO_SystemState", new Byte[] { 0xFF }),
- // seal the display to lock against changes
- new RecoveryRegisterItem("GENESISFLOW_SealDisplay", new Byte[] { 0x01 }),
- };
-
- ///
- /// Post programming parameters for EOL (end of line, prepare for shipping workplace)
- ///
- private static readonly List _finalizeProgrammingEol = new List
- {
- new RecoveryRegisterItem("GENESISFLOW_ResetAccumulators", new Byte[] { 0x01 }),
- new RecoveryRegisterItem("NFC_EraseRMA", new Byte[] { 0x01 }),
- new RecoveryRegisterItem("CUSTOMER_RebootCount", new Byte[] { 0x00 })
- };
-
- ///
- /// Actual register counter
- ///
- private Int32 _actualRegisterCtr;
-
- ///
- /// Stop register access
- ///
- public Boolean StopRegisterAccess;
-
- ///
- /// Genesis meter object
- ///
- private IGenesisMeter _currentGenesis;
-
- ///
- /// Struct to observe replacements
- ///
- private struct ReplaceVakoByCsd
- {
- public String RegisterName;
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- public List VakoValue;
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- public List CsdValue;
- }
-
- ///
- /// Ctor
- ///
- ///
- public RegisterRestorer(IGenesisMeter currentGenesis)
- {
- _currentGenesis = currentGenesis;
- RecoveryRegisters = null;
- RecoveryRegisters = new List();
- }
-
- ///
- /// Assign new genesis after reboot and keep the RegisterRestorer object.
- ///
- ///
- ///
- /// - Initial
- ///
- public void AssignGenesis(IGenesisMeter genesisMeter)
- {
- _currentGenesis = genesisMeter;
- }
-
- ///
- /// Enable comparison from external set registers for read back with written value
- ///
- ///
- /// - Initial
- ///
- public void EnableCompareExternalSetRegisters()
- {
- _pcbIdFinalRegisterRead = _currentGenesis.PcbId;
- _pcbIdWriteRegisters = _currentGenesis.PcbId;
- }
-
- ///
- /// Export list of programming parameters to file being able to use it for test purposes.
- ///
- ///
- ///
- ///
- ///
- ///
- /// - Initial.
- ///
- public static Boolean ExportRawProgrammingParametersToFile(String path, String fileName,
- List programmingParameters)
- {
- try
- {
- var fileNamePath = Path.Combine(path, fileName);
- var text = JsonConvert.SerializeObject(programmingParameters);
- File.WriteAllText(fileNamePath, text);
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- return false;
- }
-
- return true;
- }
-
- ///
- /// Import list of programming parameters from file being able to use it for test purposes.
- /// The input request the absolut path to the XX_YY_RawParameterExample.json and the filters for:
- /// - Region,
- /// - MeterSize,
- /// - "RawParams" and
- /// - ".json"
- ///
- ///
- /// path where all raw parameter examples are stored
- /// Region for configuration
- /// Meter size for programming parameters
- ///
- ///
- ///
- /// - Initial.
- ///
- public static Boolean ImportRawProgrammingParametersFromFile(String paramsRootPath, String region,
- String meterSize, List programmingParameters)
- {
- if (string.IsNullOrEmpty(paramsRootPath) ||
- string.IsNullOrEmpty(region) ||
- string.IsNullOrEmpty(meterSize))
- return false;
-
- programmingParameters.Clear();
- try
- {
- var filePathNames = Directory.GetFiles(paramsRootPath);
- if (filePathNames.Length == 0)
- return false;
-
- foreach (var filePathName in filePathNames)
- {
- var fileName = Path.GetFileName(filePathName);
- if (fileName.Contains(region) &&
- fileName.Contains(meterSize) &&
- fileName.Contains("RawParams") &&
- fileName.Contains(".json"))
- {
- var rawParamsFilePathMane = Path.Combine(paramsRootPath, fileName);
- if (!File.Exists(rawParamsFilePathMane))
- return false;
-
- var text = File.ReadAllText(filePathName);
- var progParams = JsonConvert.DeserializeObject>(text);
- programmingParameters.AddRange(progParams);
- return true;
- }
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- return false;
- }
-
- return false;
- }
-
- ///
- /// Process the raw programming parameters got from the database or meanwhile in raw-format stored to file
- /// being able to fill the register restorer from external with values and test the byte-wise reverting
- /// of the parameter (optional un-reverted if defined in the list ).
- /// The priority of the parameters forced by its source is:
- /// - CSD (highest),
- /// - VAKO,
- /// - Order based or standard config (lowest).
- ///
- /// unprocessed data, not filtered by the priority and un-reversed
- /// output as recovery registers reduced to the real needed ones and
- /// processed as reverted or non-reverted values which directly can be written to the meter using the
- /// meter specific "IGenesisMeter.WriteRegister"
- /// error message for caller
- ///
- ///
- /// - Initial imported from .
- ///
- ///
- /// - Return error message,
- /// - Requirement to fulfill the at least one parameter has to be a CSD parameter as initially all programming
- /// parameters are going to be preset with the default values (coming from the Web-API). After this they are
- /// going to be overwritten with the VAKO (variant configuration) and finally again with the CSD of the
- /// customer if required.
- ///
- ///
- /// - Debug for overwriting VAKO with CSD including real values.
- ///
- public static StatusReturn RawProgrammingParametersFilterAndSort(List rawProgParams,
- List recoveryRegisters, out String errorMsg)
- {
- errorMsg = "";
- try
- {
- if (rawProgParams == null || rawProgParams.Count == 0)
- {
- return StatusReturn.Failed;
- }
-
- // Create DEBUG lists
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- var vakoRegisterList = new List();
- var csdRegisterList = new List();
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- var orderRegisterList = new List();
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- var sortableRegisterList = new List();
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- var multipleAssignedRegisterList = new List();
- // ReSharper disable once CollectionNeverQueried.Local IS FOR DEBUG
- var replacedVakoFromCsdList = new List();
-
- // 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 rawProgParams)
- {
- // reverse byte order for all parameters except those listed below
- if (!string.IsNullOrEmpty(proPar.RegisterName))
- {
- // Catch multiple assignments
- if (sortableRegisterList.Any(a => proPar.RegisterName.Equals(a)))
- multipleAssignedRegisterList.Add(proPar.RegisterName);
-
- // Fill DEBUG lists START with all registers even if they are multiple assigned
- sortableRegisterList.Add(proPar.RegisterName);
-
- switch (proPar.Source)
- {
- case ProgrammingSource.Vako:
- vakoRegisterList.Add(proPar.RegisterName);
- break;
- case ProgrammingSource.Csd:
- csdRegisterList.Add(proPar.RegisterName);
- break;
- case ProgrammingSource.Order:
- orderRegisterList.Add(proPar.RegisterName);
- break;
- }
-
- if (_unReversedParameters.Contains(proPar.RegisterName))
- {
- // Add parameter if it is not in the list
- if (sortableProgrammingParameters.All(a => !proPar.RegisterName.Equals(a.RegisterName)))
- {
- sortableProgrammingParameters.Add(proPar);
- continue;
- }
- // if parameter from VAKO is in the list and the new is from CSD, replace this with CSD
- if (proPar.Source == ProgrammingSource.Csd && sortableProgrammingParameters.Any(a =>
- proPar.RegisterName.Equals(a.RegisterName) && a.Source == ProgrammingSource.Vako))
- {
- var removeProPar =
- sortableProgrammingParameters.LastOrDefault(a => proPar.RegisterName.Equals(a.RegisterName));
-
- var replace = new ReplaceVakoByCsd
- {
- RegisterName = proPar.RegisterName,
- VakoValue = new List(),
- CsdValue = new List()
- };
-
- if (removeProPar != null)
- {
- replace.VakoValue.AddRange(removeProPar.RegisterValue);
- replace.CsdValue.AddRange(proPar.RegisterValue);
- replacedVakoFromCsdList.Add(replace);
-
- sortableProgrammingParameters.Remove(removeProPar);
- sortableProgrammingParameters.Add(proPar);
- }
- }
- }
- else
- {
- // ATTENTION: These parameters are coming out of the DB in wrong byte order and needed
- // to be reversed for the entire sequence
- var reversedValue = proPar.RegisterValue.Reverse().ToArray();
-
- // Add parameter if it is not in the list
- if (sortableProgrammingParameters.All(a => !proPar.RegisterName.Equals(a.RegisterName)))
- {
- sortableProgrammingParameters.Add(new ProgrammingParameters(proPar.RegisterName,
- reversedValue, proPar.Source));
- continue;
- }
- // if parameter from VAKO is in the list and the new is from CSD, replace this with CSD
- if (proPar.Source == ProgrammingSource.Csd && sortableProgrammingParameters.Any(a =>
- proPar.RegisterName.Equals(a.RegisterName) && a.Source == ProgrammingSource.Vako))
- {
- var removeProPar =
- sortableProgrammingParameters.LastOrDefault(a => proPar.RegisterName.Equals(a.RegisterName));
-
- var replace = new ReplaceVakoByCsd
- {
- RegisterName = proPar.RegisterName,
- VakoValue = new List(),
- CsdValue = new List()
- };
-
- if (removeProPar != null)
- {
- replace.VakoValue.AddRange(removeProPar.RegisterValue);
- replace.CsdValue.AddRange(reversedValue);
- replacedVakoFromCsdList.Add(replace);
-
- sortableProgrammingParameters.Remove(removeProPar);
- sortableProgrammingParameters.Add(new ProgrammingParameters(proPar.RegisterName,
- reversedValue, proPar.Source));
- }
- }
- }
- } // register for this FW is defined
- else
- {
- return StatusReturn.Failed;
- }
- }
-
- // Sort the programming parameters coming from DB (VAKO/CSD)
- sortableProgrammingParameters.Sort((x, y) => string.Compare(x.RegisterName, y.RegisterName,
- StringComparison.Ordinal));
-
- // Sort DEBUG lists
- csdRegisterList.Sort();
- vakoRegisterList.Sort();
- orderRegisterList.Sort();
- sortableRegisterList.Sort();
- multipleAssignedRegisterList.Sort();
- replacedVakoFromCsdList.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(proPar.RegisterName, proPar.RegisterValue);
- recoveryRegisters.Add(recReg);
- }
- }
-
- // Requirement to fulfill that at least one parameter has to be a CSD parameter
- if (csdRegisterList.Count == 0)
- {
- errorMsg = Resources.StrErrorMsgCsdMissing;
- return StatusReturn.Failed;
- }
-
- return StatusReturn.Okay;
- }
- catch (Exception)
- {
- return StatusReturn.Failed;
- }
- }
-
- ///
- /// Collect programming parameters from DB.
- ///
- ///
- /// registers key value pair from database
- /// error message from parameter analysis
- /// 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.
- ///
- ///
- /// - Removed prohibited parameters.
- ///
- ///
- /// - Added un-reversed parameters based on data type (string, uint128).
- ///
- ///
- /// - Check and validate register values with installed or intended to be installed FW and given
- /// configuration.json.
- ///
- ///
- /// - Exported register range check to .
- ///
- ///
- /// - Debug lists for CSD and VAKO parameters.
- ///
- ///
- /// - Sorting, filtering for VAKO, CSD and order, reverting or un-reverting parameter value order exported
- /// for the ability to load the raw programming parameters from any source and check the correct processing.
- /// This will be especially used for unit-tests
- ///
- ///
- /// - Error message.
- ///
- public static StatusReturn DownloadProgrammingParametersFromDb(String pcbId,
- List recoveryRegistersDb, out String errorMsg)
- {
- errorMsg = "";
- try
- {
- var url = $"{ServiceUrls.GenesisFinalCheckServiceUrl()}GetProgrammingParameters?PcbID={pcbId}";
- var ppJson = LocalWebRequest.GetRequest(url, 30000);
-
- if (string.IsNullOrEmpty(ppJson))
- {
- return StatusReturn.Failed;
- }
-
- var programmingParameters = JsonConvert.DeserializeObject>(ppJson);
-
- if (programmingParameters == null || programmingParameters.Count == 0)
- {
- return StatusReturn.Failed;
- }
-
- return RawProgrammingParametersFilterAndSort(programmingParameters, recoveryRegistersDb, out errorMsg);
- }
- catch (Exception)
- {
- return StatusReturn.Failed;
- }
- }
-
- ///
- /// Avoid doubling of register restore on subsequent FW-Update trials.
- ///
- /// true if registers already backed up
- ///
- /// - Initial.
- ///
- public Boolean RegisterRestoreExecuted()
- {
- if (_currentGenesis == null)
- return false;
- if (_currentGenesis.PcbId != _pcbIdFinalRegisterRead)
- return false;
- return _finalRegisters.Count > 0;
- }
-
- ///
- /// EOL (end of line) programming contains a reset of the accumulators. Else it is identical with recover
- /// registers.
- ///
- /// list of registers to update from database without special sequence
- ///
- /// true if setup succeeded
- ///
- /// - Initial.
- ///
- public StatusReturn EolProgrammingRegisters(List recoveryRegistersDb)
- {
- // mark EOL as true to force accu reset
- return WriteRegisters(recoveryRegistersDb, true);
- }
-
- ///
- /// Validate the range of the register.
- ///
- /// register key value pair
- /// register definition by configuration.json
- /// error message if range check failed
- /// check default value and supply warning
- /// status
- ///
- /// - Initial, imported from
- ///
- ///
- /// - Leave the message generation to the
- ///
- public static StatusReturn ValidateRegisterRange(RecoveryRegisterItem recReg,
- RegisterDefinition regDef, out String errorMessage, Boolean checkDefault = false)
- {
-
- // Error message will be returned on failed check or on default value
- errorMessage = null;
- try
- {
- // check the limits and avoid writing if not in range
- return RegisterCheck.CheckRange(regDef, recReg.WriteValue, out errorMessage, checkDefault);
- }
- catch (Exception ex)
- {
- errorMessage = ex.Message;
- return StatusReturn.Failed;
- }
- }
-
- ///
- /// Recover all registers set from caller. Additional preparation and finalization will be added.
- /// settings.
- ///
- /// list of registers to update from database without special sequence
- ///
- /// EOL (end of line) programming with accu reset
- /// true if restoring succeeded
- ///
- /// - Initial.
- ///
- ///
- /// - Return true if already recovered,
- /// - replace _restoreRegisters with new value.
- ///
- ///
- /// - Added preparation and finalization of register recovery giving the ability to log this in the report.
- ///
- ///
- /// - Moved register dictionary value set to inner try catch loop to avoid early exit if one register is
- /// unknown.
- ///
- ///
- /// - Logging of some exception messages.
- ///
- ///
- /// - EOL sequence for accumulators reset,
- /// - Remind pcbId as already recovered before the true return,
- /// - Exclude lock of repeated execution for EOL.
- ///
- ///
- /// - Avoid writing of parameters if not writable. The DB delivers parameters which exclusively have to be
- /// compared to the specified value.
- ///
- ///
- /// - Register list changed from RegisterDefinition to RecoveryRegisterItem list,
- /// - Preset RecoveryRegisters if not set as those have to be compared later on.
- ///
- ///
- /// - Add only registers to recovery list which are found in the generated register list based on installed
- /// applications.
- ///
- ///
- /// - Avoid writing of NOT writable registers.
- ///
- ///
- /// - Check register limits, if those are out of range avoid writing and log warning message.
- ///
- ///
- /// - Exported register range check to .
- ///
- ///
- /// - Removed skip recovery if already done in previous run to enable a retry.
- ///
- ///
- /// - Seal display and Sensus radio to EMEA finalization.
- ///
- ///
- /// - Exported write routines to .
- ///
- public StatusReturn WriteRegisters(List recoveryRegistersDb, Boolean eolProgramming = false)
- {
- if (_currentGenesis == null ||
- string.IsNullOrEmpty(_currentGenesis.PcbId) ||
- recoveryRegistersDb == null ||
- recoveryRegistersDb.Count == 0)
- return StatusReturn.Failed;
-
- // preset recovery registers if not already set
- if (RecoveryRegisters == null)
- {
- RecoveryRegisters = new List();
- }
- if (RecoveryRegisters.Count == 0)
- {
- RecoveryRegisters = recoveryRegistersDb;
- }
-
- StopRegisterAccess = false;
- _actualRegisterCtr = 0;
-
- // Build string list for debug
- _dbParameterRegisterList.Clear();
- _dbParameterRegisterList = recoveryRegistersDb.Select(register => register.RegisterIdent).ToList();
- _dbParameterRegisterList.Sort();
-
- // write values to Genesis
- _currentGenesis.ReLogin();
- if (!_currentGenesis.IsLoggedOn)
- return StatusReturn.Failed;
-
- // get the pre-defined dictionary
- var meterRegisters = _currentGenesis.GetConfigRegistersDefinitions();
-
- // prepare list for finalization depending on SENSUSRADIO installation
- var finalizeProgrammingAll = new List();
-
- // add EOL (shipping reset of accumulators, alarms and setup of manufacturing date)
- if (eolProgramming)
- {
- finalizeProgrammingAll.AddRange(_finalizeProgrammingEol.Where(finalReg =>
- meterRegisters.MeterRegisterDic.Any(x => x.Key.GetIdent().Contains(finalReg.RegisterIdent))));
- }
-
- // add only registers which are defined as needed to restore and in the found register list
- // from installed applications
- finalizeProgrammingAll.AddRange(_finalizeProgrammingAll.Where(finalReg =>
- meterRegisters.MeterRegisterDic.Any(x => x.Key.GetIdent().Contains(finalReg.RegisterIdent))));
-
- // add special registers for EMEA version
- if (_currentGenesis.Region.Equals("EMEA"))
- {
- finalizeProgrammingAll.AddRange(_finalizeProgrammingEmea.Where(finalReg =>
- meterRegisters.MeterRegisterDic.Any(x => x.Key.GetIdent().Contains(finalReg.RegisterIdent))));
- }
-
- // set the process counter
- 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));
-
- if (StatusReturn.Failed == WriteRegisterParameterSet(_prepareProgramming, recRegistersCount, meterRegisters))
- {
- // the logout will force the radio app to activate the settings
- _currentGenesis?.Logout();
- return StatusReturn.Failed;
- }
-
- // register recovery
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(Resources.StrRegisterRecoveryExec,
- actualProcessMessage: Resources.StrRegisterRecoveryExec));
-
- if (StatusReturn.Failed == WriteRegisterParameterSet(recoveryRegistersDb, recRegistersCount, meterRegisters))
- {
- // the logout will force the radio app to activate the settings
- _currentGenesis?.Logout();
- return StatusReturn.Failed;
- }
-
- // finalize recovery
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(Resources.StrRegisterRecoveryFinalization,
- actualProcessMessage: Resources.StrRegisterRecoveryFinalization));
-
- if (StatusReturn.Failed == WriteRegisterParameterSet(finalizeProgrammingAll, recRegistersCount, meterRegisters))
- {
- // the logout will force the radio app to activate the settings
- _currentGenesis?.Logout();
- return StatusReturn.Failed;
- }
-
- // remind pcbId of this run to avoid endless repetition
- _pcbIdWriteRegisters = _currentGenesis.PcbId;
-
- // the logout will force the radio app to activate the settings
- _currentGenesis?.Logout();
-
- // Wait for completion as storing may need a certain time
- Thread.Sleep(1000);
-
- return StatusReturn.Okay;
- }
-
- ///
- /// Write a parameter set:
- /// -
- ///
- ///
- ///
- ///
- ///
- ///
- /// - Initial imported from .
- ///
- private StatusReturn WriteRegisterParameterSet(List recoveryRegistersDb, Int32 recRegistersCount,
- MeterRegisters meterRegisters)
- {
- foreach (var recReg in recoveryRegistersDb)
- {
- _actualRegisterCtr++;
- var overallProcessCtrPercent = 100.0 * _actualRegisterCtr / recRegistersCount;
-
- RegisterDefinition regDef;
-
- try
- {
- // If this call does not throw an exception, the register is present
- regDef = meterRegisters.GetRegisterDefinitionByName(recReg.RegisterIdent);
- }
- catch (Exception ex)
- {
- _currentGenesis.WriteLog(ex.Message);
- regDef = null;
- }
-
- if (null == regDef)
- {
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(
- $@"{Resources.StrWriteRegister} {_actualRegisterCtr} / {recRegistersCount}",
- overallProcessCtrPercent, Resources.StrErrorMsgRegisterNotFound + " Register: " +
- recReg.RegisterIdent));
- return StatusReturn.Failed;
- }
-
- // avoid writing of NOT writable registers
- if (regDef.RegisterDetail.Privilege.Lvl8 != Access.WO
- && regDef.RegisterDetail.Privilege.Lvl8 != Access.RW)
- continue;
-
- // check the limits and avoid writing if not in range
- var retVal = ValidateRegisterRange(recReg, regDef, out var errorMessage);
- if (StatusReturn.Failed == retVal)
- {
- _currentGenesis.WriteLog(errorMessage);
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(
- $@"{Resources.StrWriteRegister} {_actualRegisterCtr} / {recRegistersCount}",
- overallProcessCtrPercent, Resources.StrRegisterValueOutOfRange + " " + errorMessage));
- return StatusReturn.Failed;
- }
-
- if (!_currentGenesis.WriteRegister(recReg.RegisterIdent, recReg.WriteValue))
- {
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(
- $@"{Resources.StrWriteRegister} {_actualRegisterCtr} / {recRegistersCount}",
- overallProcessCtrPercent, Resources.StrErrorMsgRegisterWrite + " Register: " +
- recReg.RegisterIdent));
- return StatusReturn.Failed;
-
- }
- var strRawAndConvertedValue = "";
- try
- {
- strRawAndConvertedValue = RegisterConverter.GetRegisterContentText(regDef, recReg.WriteValue);
- }
- catch (Exception ex)
- {
- _currentGenesis.WriteLog("Could not convert register value of " + recReg.RegisterIdent +
- "; " + ex.Message);
- }
- finally
- {
- var actualProcessMsg = $"{Resources.StrWriteRegister}: {strRawAndConvertedValue} ";
-
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(
- $@"{Resources.StrWriteRegister} {_actualRegisterCtr} / {recRegistersCount}",
- overallProcessCtrPercent, actualProcessMsg));
- }
-
- if (StopRegisterAccess)
- break;
- }
-
- return StatusReturn.Okay;
- }
-
- ///
- /// Compare all registers which can be restored without new access to meter.
- /// Precondition:
- /// - The _restoreRegisters has to be filled with all registers being able to restore (RW),
- /// - The _finalReadRegisters has to be filled.
- ///
- /// true if equal
- ///
- /// - Initial.
- ///
- ///
- /// - Compare registers reactivated based on new interface (configuration.json) with new
- /// "StaticType": “approximate”.
- ///
- ///
- /// - Removed as those will change on e.g. FW update.
- ///
- ///
- /// - Avoid message event if message is empty.
- ///
- ///
- /// - Remind registers which failed the comparison including values.
- ///
- ///
- /// - Register list changed from RegisterDefinition to RecoveryRegisterItem list.
- ///
- ///
- /// - Removed all registers from comparison which are neither static nor approximate.
- ///
- ///
- /// - Exception logging extended,
- /// - Data size base on write data size as this may be shorter than the read data size which is always filled up
- /// to a 4 byte chunk size.
- ///
- ///
- /// - Add only registers to recovery list which are found in the generated register list based on installed applications.
- ///
- ///
- /// - Used RecoveryRegisters WriteValue and ReadBackValue for comparison.
- ///
- ///
- /// - Hash password and encryption key with SHA256.
- ///
- public Boolean CompareRegisters()
- {
- if (_pcbIdFinalRegisterRead != _pcbIdWriteRegisters ||
- RecoveryRegisters == null)
- return false;
-
- StopRegisterAccess = false;
- _actualRegisterCtr = 0;
- var retVal = true;
-
- // DEBUG
- _failedComparisonRegisters?.Clear();
-
- // build a string list of the registers being able to sort those
- var registerNames = RecoveryRegisters.Select(register => register.RegisterIdent).ToList();
- // Remove all excluded registers
- foreach (var regName in _excludedFromCompareParameters.Where(regName => registerNames.Any(reg => reg == regName)))
- {
- registerNames.Remove(regName);
- }
- // sort the list of register names
- registerNames.Sort();
- // limit the count to 1 to avoid division by zero
- var registersCount = registerNames.Count > 0 ? registerNames.Count : 1;
-
- // get the pre-defined dictionary
- var meterRegisters = _currentGenesis.GetConfigRegistersDefinitions();
-
- // access every register
- foreach (var regName in registerNames)
- {
- _actualRegisterCtr++;
- var overallProcessCtrPercent = 100.0 * _actualRegisterCtr / registersCount;
-
- RegisterDefinition regDef = null;
- try
- {
- // take the register properties from configuration.json
- regDef = meterRegisters.GetRegisterDefinitionByName(regName);
- }
- catch (Exception ex)
- {
- _currentGenesis.WriteLog("Meter register not defined or application not installed " +
- regName + "; " + ex.Message);
- }
-
- // skip all registers from comparison which are neither static nor approximate or not detected
- // in meter registers based on installed applications
- if (regDef == null || !regDef.RestoreCapability.CheckRestoreCapability())
- {
- continue;
- }
-
- try
- {
- // Get the raw byte array of this register
- var recReg = RecoveryRegisters.First(reg => reg.RegisterIdent.Equals(regName));
- var writtenValue = recReg.WriteValue;
- var readBackValue = recReg.ReadBackValue;
-
- // If any value is null then there is nothing to compare
- if (writtenValue == null || readBackValue == null)
- {
- _failedComparisonRegisters?.Add(new RecoveryRegisterItem(regName, writtenValue, readBackValue));
- 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!
- var dataSize = writtenValue.Length;
-
- var strRequiredRegisterValue = "";
- try
- {
- var isApproximated = false;
- var isIdentical = false;
- if (regDef.RegisterDetail.StaticType == StaticType.ReadBackApproximated)
- {
- Int64 restoreValue = 0;
- Int64 finalValue = 0;
- if (regDef.DataType.Name.Equals("Int32"))
- {
- restoreValue = RegisterConverter.ByteArrayToValue(writtenValue);
- finalValue = RegisterConverter.ByteArrayToValue(readBackValue);
- }
- else if (regDef.DataType.Name.Equals("UInt32"))
- {
- restoreValue = RegisterConverter.ByteArrayToValue(writtenValue);
- finalValue = RegisterConverter.ByteArrayToValue(readBackValue);
- }
- // Just half of number range will work due to cast to Int64
- else if (regDef.DataType.Name.Equals("UInt64"))
- {
- restoreValue = (Int64)RegisterConverter.ByteArrayToValue(writtenValue);
- finalValue = (Int64)RegisterConverter.ByteArrayToValue(readBackValue);
- }
- else if (regDef.DataType.Name.Equals("Int64"))
- {
- restoreValue = RegisterConverter.ByteArrayToValue(writtenValue);
- finalValue = RegisterConverter.ByteArrayToValue(readBackValue);
- }
- else if (regDef.DataType.Name.Equals("Byte"))
- {
- restoreValue = RegisterConverter.ByteArrayToValue(writtenValue);
- finalValue = RegisterConverter.ByteArrayToValue(readBackValue);
- }
- else if (regDef.DataType.Name.Equals("SByte"))
- {
- restoreValue = RegisterConverter.ByteArrayToValue(writtenValue);
- finalValue = RegisterConverter.ByteArrayToValue(readBackValue);
- }
- // Check limited to +/- 3
- if (restoreValue - 3 <= finalValue && restoreValue + 3 >= finalValue)
- {
- isApproximated = true;
- }
- }
- else
- {
- for (var c = 0; c < dataSize; c++)
- {
- if (writtenValue[c] != readBackValue[c])
- {
- isIdentical = false;
- break;
- }
- isIdentical = true;
- }
- }
- // convert register content to text with raw and converted value depending on data type
- strRequiredRegisterValue =
- RegisterConverter.GetRegisterContentText(regDef, writtenValue);
- if (readBackValue != null && (isIdentical || isApproximated))
- {
- strRequiredRegisterValue += $" - {Resources.StrRegisterCompareSucceeded}";
- }
- else
- {
- var encryptRawData = regName.Contains("EncryptionKey") || regName.Contains("Password");
-
- var strReadBackRegisterValue = RegisterConverter.GetRegisterRawText(regDef, readBackValue,
- encryptRawData);
-
- strRequiredRegisterValue += $" - {Resources.StrMeterValue} ({strReadBackRegisterValue})h" +
- $" - {Resources.StrRegisterCompareFailed}";
- _failedComparisonRegisters?.Add(new RecoveryRegisterItem(regName, writtenValue,
- readBackValue));
- retVal = false;
- }
- }
- catch (Exception ex)
- {
- _currentGenesis.WriteLog("Could not compare register value of " + regName + "; " + ex.Message);
- }
- finally
- {
- var actualProcessMsg = $"{Resources.StrRegisterCompare} {strRequiredRegisterValue} ";
-
- // Avoid message if nothing to tell
- if (!string.IsNullOrEmpty(strRequiredRegisterValue))
- {
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs($@"{Resources.StrRegisterCompare}" +
- $@" {_actualRegisterCtr} / {registersCount}",
- overallProcessCtrPercent, actualProcessMsg));
- }
- }
-
- if (StopRegisterAccess)
- break;
- }
- catch (Exception ex)
- {
- _currentGenesis.WriteLog("Could not access register for comparison " + regName + "; " + ex.Message);
- }
- }
- return retVal;
- }
-
- ///
- /// Read the registers after the update for comparision. Build the post update registers here,
- /// because an update may have changed the registers (new or removed registers).
- ///
- /// true if registers could be read
- ///
- /// - Initial.
- ///
- ///
- /// - Build here the post update registers, they may have changed due to update!
- ///
- ///
- /// - Clear pre update registers if post indicates a different PCB ID to avoid wrong overwriting of
- /// registers to non-matching new meter.
- ///
- ///
- /// - Return true if already executed in previous run.
- ///
- ///
- /// - Return false if PcbId between initial- and final-read does NOT match return false.
- ///
- ///
- /// - Allow final read out as often as called even if done before.
- ///
- ///
- /// - Register list changed from RegisterDefinition to RecoveryRegisterItem list.
- ///
- ///
- /// - Backup _finalRegisters to RecoveryRegisters.
- ///
- ///
- /// - Check readBack value for null.
- ///
- public Boolean FinalReadRegisters()
- {
- if (_currentGenesis == null)
- return false;
-
- Boolean retVal;
- try
- {
-
- // create a dictionary for final read being able to compare those with the initial read and restored
- if (!BuildReadableRegisterDictionary(ref _finalRegisters))
- return false;
-
- // log to report file the after update register read string
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs($@"{Resources.StrReadRegister}", 0,
- Resources.StrReadRegistersAfterUpdate));
-
- // Build string list for debug
- _finalRegisterList.Clear();
- _finalRegisterList = _finalRegisters.Select(register => register.RegisterIdent).ToList();
- _finalRegisterList.Sort();
-
- // executes login read logout
- retVal = ReadRegistersSet(ref _finalRegisters);
-
- // backup read data to RecoveryRegisters
- if (RecoveryRegisters != null && _finalRegisters != null)
- {
- foreach (var recReg in RecoveryRegisters)
- {
- foreach (var finalReg in _finalRegisters.Where(finalReg =>
- recReg.RegisterIdent.Equals(finalReg.RegisterIdent)))
- {
- if (finalReg.ReadBackValue == null)
- {
- recReg.ReadBackValue = null;
- continue;
- }
-
- recReg.ReadBackValue = new Byte[finalReg.ReadBackValue.Length];
- for (var c = 0; c < finalReg.ReadBackValue.Length; c++)
- recReg.ReadBackValue[c] = finalReg.ReadBackValue[c];
- }
- }
- }
-
- // remind the PCB ID before update for comparison
- _pcbIdFinalRegisterRead = _currentGenesis.PcbId;
-
- }
- catch (Exception ex)
- {
- _currentGenesis.WriteLog("Copying read back data failed " + ex.Message);
- retVal = false;
- }
- return retVal;
- }
-
- ///
- /// Get DEFINED registers from GenesisMeter class and read all registers which are flagged with
- /// read write (RW) or read only (RO). Build a list of all registers being able to restore flagged
- /// with equals ".
- /// The defined registers are based on the "configuration.json" and the installed application with
- /// a specific version.
- ///
- /// true if registers could be read
- ///
- /// - Initial.
- ///
- ///
- /// - Stored registers before and after update.
- ///
- ///
- /// - Extended register check.
- ///
- ///
- /// - Removed after update registers and moved them to FinalReadRegisters. They may have changed
- /// during the update.
- ///
- ///
- /// - Deny register pre update if _pcbIdPreUpdate indicates, that this has been already processed.
- ///
- ///
- /// - Removed login/logout,
- /// - if _initialReadRegisters and _restoreRegisters are filled, return true.
- ///
- ///
- /// - Register list changed from RegisterDefinition to RecoveryRegisterItem list.
- ///
- public Boolean InitialReadRegisters()
- {
- if (_currentGenesis == null)
- return false;
-
- // deny update of registers if already done
- if (_pcbIdInitialRegisterRead == _currentGenesis.PcbId &&
- _initialRegisters.Count > 0)
- return true;
-
- // remind the PCB ID before update for comparison
- _pcbIdInitialRegisterRead = _currentGenesis.PcbId;
-
- // create the dictionaries out of the configuration.json
- if (!BuildReadableRegisterDictionary(ref _initialRegisters))
- return false;
-
- // log to report file the initial register read string
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs($@"{Resources.StrReadRegister}", 0,
- Resources.StrReadRegistersBeforeUpdate));
-
- // Build string list for debug
- _initialRegisterList.Clear();
- _initialRegisterList = _initialRegisters.Select(register => register.RegisterIdent).ToList();
- _initialRegisterList.Sort();
-
- return ReadRegistersSet(ref _initialRegisters);
- }
-
- ///
- /// Get DEFINED registers from GenesisMeter class and build a list all registers which are flagged
- /// with read write (RW) or read only (RO).
- /// The defined registers are based on the "configuration.json" and the installed application with
- /// a specific version.
- ///
- /// all readable registers dictionary creation
- /// true if register dictionary is not empty
- /// true if registers could be read
- ///
- /// - Initial from .
- ///
- ///
- /// - Register list changed from RegisterDefinition to RecoveryRegisterItem list.
- ///
- ///
- /// - Excluded registers which do not contain useful information.
- ///
- public Boolean BuildReadableRegisterDictionary(ref List registers)
- {
- if (_currentGenesis == null || registers == null)
- return false;
-
- registers.Clear();
- _readableRegisterList.Clear();
-
- // get the pre-defined dictionary
- var meterRegisters = _currentGenesis.GetConfigRegistersDefinitions();
- // extract all registers which can be read and create two dictionaries for before update to safe program
- // internally the register content for comparison ability. Exclude register which contain no useful info.
- foreach (var reg in meterRegisters.MeterRegisterDic.Where(r => r.Key.RegisterDetail.Version.First != null
- && r.Key.RegisterDetail.Version.Last != null && r.Key.RestoreCapability.StaticTypeValue != null
- && r.Key.DataType != typeof(Rpc) && r.Key.IsAvailable &&
- (r.Key.RegisterDetail.Privilege.Lvl8 == Access.RW || r.Key.RegisterDetail.Privilege.Lvl8 == Access.RO)
- && _excludedFromReadParameters.All(regName => regName != r.Key.GetIdent())))
- {
- var registerIdent = reg.Key.GetIdent();
- registers.Add(new RecoveryRegisterItem(registerIdent, reg.Value));
- _readableRegisterList.Add(registerIdent);
- }
-
- _readableRegisterList.Sort();
- registers.Sort((a, b) => String.Compare(a.RegisterIdent, b.RegisterIdent, StringComparison.Ordinal));
- return registers.Count > 0;
- }
-
- ///
- /// Get DEFINED registers from GenesisMeter class and read all registers which are flagged with read write
- /// (RW) or read only (RO).
- /// The defined registers are based on the "configuration.json" and the installed application with a specific
- /// version.
- ///
- /// true if registers could be read
- ///
- /// - Initial.
- ///
- ///
- /// - Register list changed from RegisterDefinition to RecoveryRegisterItem list.
- ///
- public Boolean ReadRegisters()
- {
- if (_currentGenesis == null)
- return false;
-
- // temporary list of registers just for read and log without keeping them alive
- var registers = new List();
-
- if (!BuildReadableRegisterDictionary(ref registers))
- return false;
-
- // log to report file the initial register read string
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs($@"{Resources.StrReadRegister}", 0,
- Resources.StrReadRegistersBeforeUpdate));
-
- return ReadRegistersSet(ref registers);
- }
-
- ///
- /// Read predefined registers from RecoveryRegisters.
- ///
- /// true if registers could be read
- ///
- /// - Initial.
- ///
- public Boolean ReadPresetRegisters()
- {
- if (_currentGenesis == null || RecoveryRegisters == null || RecoveryRegisters.Count == 0)
- return false;
-
- // Assume that this meter shall be used for comparison even if nothing has been written.
- // The RecoveryRegisters can be preset with a writeValue being able to use FinalReadRegisters
- // and compare the readBackValue from those with the preset writeValue.
- _pcbIdWriteRegisters = _currentGenesis.PcbId;
- _pcbIdFinalRegisterRead = _currentGenesis.PcbId;
-
- return ReadRegistersSet(ref RecoveryRegisters);
- }
-
- ///
- /// Register read loop.
- /// All registers needed to be read from the Genesis meter as they are only prepared as template and NOT filled
- /// with the register data!
- /// The uses the overall process text and value for user information process
- /// bar and text and the actual process text for logging to the report file!
- /// Executes login, read cycle and logout.
- ///
- /// registers to read
- /// true if registers could be read
- ///
- /// - Initial.
- ///
- ///
- /// - Set value to actual process message.
- ///
- ///
- /// - Added PCB ID to logging.
- ///
- ///
- /// - Removed PCB ID from logging.
- ///
- ///
- /// - Simplified input of set of registers to read.
- ///
- ///
- /// - Set raw values in register dictionaries.
- ///
- ///
- /// - Extended try catch to avoid break on one register failed.
- ///
- ///
- /// - Filtered restore registers to access only if assigned,
- /// - Logging of some exception messages.
- ///
- ///
- /// - Register list changed from RegisterDefinition to RecoveryRegisterItem list.
- ///
- private Boolean ReadRegistersSet(ref List registers)
- {
- if (_currentGenesis == null)
- return false;
- StopRegisterAccess = false;
- _actualRegisterCtr = 0;
-
- // read values from Genesis
- _currentGenesis.ReLogin();
- if (!_currentGenesis.IsLoggedOn)
- return false;
-
- // build a string list of the registers being able to sort those
- var registerNames = registers.Select(register => register.RegisterIdent).ToList();
- // sort the list of register names
- registerNames.Sort();
- // limit the count to 1 to avoid division by zero
- var registersCount = registerNames.Count > 0 ? registerNames.Count : 1;
-
- // get the pre-defined dictionary
- var meterRegisters = _currentGenesis.GetConfigRegistersDefinitions();
- // access every register
- foreach (var regName in registerNames)
- {
- _actualRegisterCtr++;
-
- // get register definition to analyze the data type and therefore the expected length
- var regDef = meterRegisters.GetRegisterDefinitionByName(regName);
-
- // get the register out of the given list
- var register = registers.FirstOrDefault(reg => reg.RegisterIdent.Equals(regName));
-
- var overallProcessCtrPercent = 100.0 * _actualRegisterCtr / registersCount;
-
- try
- {
- var rawRegister = _currentGenesis.ReadRegister(regName, RegisterConverter.SizeOf(regDef));
- try
- {
- if (register != null && rawRegister != null)
- {
- register.ReadBackValue = new Byte[rawRegister.Length];
- for (var c = 0; c < rawRegister.Length; c++)
- register.ReadBackValue[c] = rawRegister[c];
- }
- }
- catch (Exception ex)
- {
- _currentGenesis.WriteLog("Register value backup failed " + regName + "; " + ex.Message);
- }
-
- var strRawAndConvertedValue = $"{regName} - ?";
- try
- {
- if (rawRegister != null)
- {
- // convert register content to text with raw and converted value depending on data type
- strRawAndConvertedValue = RegisterConverter.GetRegisterContentText(regDef, rawRegister);
- }
- }
- catch (Exception ex)
- {
- _currentGenesis.WriteLog("Register value conversion failed " + regName + "; " + ex.Message);
- }
- finally
- {
- var actualProcessMsg = $"{Resources.StrReadRegister}: {strRawAndConvertedValue} ";
-
- OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs($@"{Resources.StrReadRegister}" +
- $@" {_actualRegisterCtr} / {registersCount}",
- overallProcessCtrPercent, actualProcessMsg));
- }
-
- if (StopRegisterAccess)
- break;
- }
- catch (Exception ex)
- {
- _currentGenesis.WriteLog("Register value read access failed " + regName + "; " + ex.Message);
- }
- }
- _currentGenesis.Logout();
- return true;
- }
- }
-}
diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProcessStatesDef.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProcessStatesDef.cs
index 45ae18aa..384c954a 100644
--- a/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProcessStatesDef.cs
+++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProcessStatesDef.cs
@@ -139,7 +139,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
}
///
- public List GetAllEolRelevantProcesses()
+ public List GetAllProductionProcesses()
{
var sortedList = StateContainer
.Where(y => y.ProductionProcessNo != null)
diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckRadio.cs.bak b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckRadio.cs.bak
new file mode 100644
index 00000000..ac3db873
--- /dev/null
+++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckRadio.cs.bak
@@ -0,0 +1,829 @@
+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 Xylem.Common.CommonCore.Configuration;
+using Xylem.Common.CommonCore.Consts;
+using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
+using Xylem.Common.Logic.ProductionOrderCore;
+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 Button = System.Windows.Controls.Button;
+// ReSharper disable UnusedAutoPropertyAccessor.Local
+
+namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses
+{
+ public class CheckRadio : BaseProductionProcess
+ {
+ ///
+ /// Maximum of expected processing steps for this process to feed the GUI progress bar.
+ /// Use the sleep 250 to create x seconds timeout;
+ ///
+ private const Int32 TimeoutLoop_ms = 250;
+ private const Int32 Timeout_s = 10;
+ private const Int32 MaxActualProgressSteps = 1000 / TimeoutLoop_ms * Timeout_s;
+
+ ///
+ /// Remind the ID of the radio result as feedback from the DB.
+ ///
+ private Int64 _radioResultCheckId;
+
+ ///
+ /// Final state of radio system.
+ ///
+ private Int32 _finalRadioSystemState;
+ ///
+ /// Reminder for specific user control
+ ///
+ private UcRadioCheck _checkRadioUserControl;
+
+ ///
+ /// Signal level successfully tested
+ ///
+ private Boolean _successSignalLevel;
+
+ ///
+ /// Radio encryption key converted to string
+ ///
+ private String _radioEncryptionKey;
+
+ ///
+ /// Test finished can be good or abort by done button to exit this production process
+ ///
+ private Boolean _testFinished;
+
+ ///
+ /// SIRT communication okay
+ ///
+ private Boolean _sirtComOkay;
+
+ private DataContainer _dataContainer;
+ private Statemashine _stateMachine;
+
+ ///
+ /// Minimum PAM signal level of SIRT got from DB
+ ///
+ private Byte? _rssiPamSirtDbMin;
+ ///
+ /// Maximum PAM signal level of SIRT got from DB
+ ///
+ private Byte? _rssiPamSirtDbMax;
+ ///
+ /// Minimum SEMI signal level of Cordonel response got from DB
+ ///
+ private Byte? _rssiSemiCordonelDbMin;
+ ///
+ /// Maximum SEMI signal level of Cordonel response got from DB
+ ///
+ private Byte? _rssiSemiCordonelDbMax;
+
+ ///
+ /// Measured from SIRT the signal strength of the Cordonel SEMI answer
+ ///
+ private Byte? _rssiSemiCordonelMeasuredBySirt;
+
+ ///
+ /// Measured from Cordonel the signal strength of the SIRT PAM received
+ ///
+ private Byte? _rssiPamSirtMeasuredByCordonel;
+
+ ///
+ /// Number of the SIRT box as these are evaluated for their signal strength
+ ///
+ private Byte _sirtBoxNr;
+
+ ///
+ /// Comport number of SIRT
+ ///
+ private Byte _sirtComport;
+
+ ///
+ /// Radio address Cordonel
+ ///
+ private UInt32 _radioAddressCordonel;
+
+ ///
+ /// Ctor
+ ///
+ public CheckRadio(String name) : base(name)
+ {
+ }
+
+ ///
+ protected override void InitUserControl()
+ {
+ UserControl = new UcRadioCheck();
+ _checkRadioUserControl = (UcRadioCheck)UserControl;
+ _checkRadioUserControl.OnResetRequested += delegate
+ {
+ Retry();
+ };
+ //_checkRadioUserControl.OnDoneRequested += delegate
+ //{
+ // SaveRssiLevelsToDb();
+ //};
+ }
+
+ ///
+ /// Check of radio signal strength, skips process on special permission or if NA region
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ ///
+ /// - Skip process on special permission or if NA region,
+ /// - Remove userControl from main screen if skipped.
+ ///
+ ///
+ /// - Fire SingleProcessState event with argument.
+ ///
+ ///
+ /// - Removed signals for and as
+ /// these will be automatically set based on return value in
+ /// .
+ ///
+ ///
+ /// - Assignment of stateMachine and dataContainer.
+ ///
+ ///
+ /// - Get encryption key moved to process to speed up
+ /// this process as this process needs to be run exclusively.
+ ///
+ ///
+ /// - EOL progress signaled.
+ ///
+ ///
+ /// - Logout at finalization,
+ /// - Log all write accesses.
+ ///
+ ///
+ /// - SkipRadioCheck not nullable.
+ ///
+ ///
+ /// - SetTestInit as bool.
+ ///
+ ///
+ /// - Separate TestInit and SirtInit (only if test shouldn't be skipped).
+ ///
+ ///
+ /// - CancellationToken.
+ ///
+ public override StatusReturn ExecuteProcess()
+ {
+ // This will force to reset all values, Sentinel and Prepare shipping will fail based on EOL Progress
+ if (Meter == null || ProductionRequirements == null ||
+ (!Meter.Region.Equals("NA") && RadioEncryptionKey?.Count == 0))
+ {
+ return StatusReturn.Failed;
+ }
+
+ // Setup all parameters being able to execute initially or repeat the test
+ TestInit();
+
+ // Check first if radio is installed,
+ // North America Region(NA) doesn't have a Sensus radio application installed
+ if (Meter.Region.Equals("NA"))
+ {
+ EolProgress.FinalRadioSystemStateCheck = EOLStatus.NA;
+ LogNewStatusMsg(Resources.StrSkippedMsgRadioCheckRegion);
+ PrepareExit();
+ return StatusReturn.Skipped;
+ }
+
+ // Starting point of time-consuming operations
+ SignalRunningState(MaxActualProgressSteps);
+
+ // If requirement forces skipping but radio is installed, it should at least be set to customer mode and checked for
+ // it.
+ // Reminder for skip radio check forced by requirements
+ var skipRadioCheck = ProductionRequirements.SkipRadioCheck;
+
+ try
+ {
+ if (!Meter.IsLoggedOn)
+ {
+ Meter.Login();
+ if (!Meter.IsLoggedOn)
+ {
+ return SetTestFailed(Resources.StrErrorMsgCordonelLogin);
+ }
+ }
+
+ // Standard run for radio signal test (RSSI)
+ if (!skipRadioCheck)
+ {
+ if (UserControl == null)
+ {
+ return SetTestFailed(Resources.StrErrorMsgRadioCheck);
+ }
+
+ // Initialize the SIRT
+ if (!SirtInit())
+ {
+ return SetTestFailed(Resources.StrErrorMsgSirt);
+ }
+
+ //FrequencyIndicator
+ var freq = RegisterConverter.ByteArrayToValue(
+ Meter.ReadRegister("SENSUSRADIO_FrequencyIndicator"));
+ _radioAddressCordonel =
+ RegisterConverter.ByteArrayToValue(Meter.ReadRegister("SENSUSRADIO_RadioAddress"));
+ ActualProcessProgress++;
+
+ var meterRawEncryptionKey = Meter.ReadRegister("SENSUSRADIO_EncryptionKey", 16);
+ var meterEncryptionKey = "";
+
+ // convert byte array to string
+ if (meterRawEncryptionKey != null)
+ {
+ meterEncryptionKey = BitConverter.ToString(meterRawEncryptionKey.ToArray()).Replace("-", "");
+ }
+
+ if (RadioEncryptionKey != null)
+ {
+ _radioEncryptionKey = RadioEncryptionKey[0].ToUpper();
+ }
+
+ // Compare the meterEncryptionKey read out from meter with the database RadioEncryptionKey
+ // got with the MeterProcessState/api/FinalCheck/GetEncryptionKey
+ if (meterRawEncryptionKey == null || RadioEncryptionKey == null ||
+ string.IsNullOrEmpty(meterEncryptionKey) || string.IsNullOrEmpty(_radioEncryptionKey) ||
+ !_radioEncryptionKey.Equals(meterEncryptionKey))
+ {
+ return SetTestFailed(Resources.StrErrorMsgRadioKey);
+ }
+
+ SuccessMsgDispatcher(Resources.StrSuccessMsgDbToMeterEncryptionKey);
+ ActualProcessProgress++;
+
+ _sirtComport = Convert.ToByte(ConfigurationManager.AppSettings[$"SirtComport{freq}"]);
+ _sirtBoxNr = Convert.ToByte(ConfigurationManager.AppSettings["SirtBoxNr"]);
+ var ucRadio = (UcRadioCheck)UserControl;
+ ucRadio.SetHeadline($"{Resources.StrStateRadioCheck} BOX: {_sirtBoxNr}");
+ LogNewStatusMsg($"{Resources.StrStateRadioCheck} Port: COM{_sirtComport}, BOX: {_sirtBoxNr}, " +
+ $"f: {freq} MHz");
+
+ // Tell the radio that something is in the slot which will impact the radio transmission
+ WriteRegisterLogAndProcessCtr(new ProgrammingParameters("SENSUSRADIO_IrDAModulePresent",
+ new Byte[] { 1 }, ProgrammingSource.ProgramInternal));
+
+ ActualProcessProgress++;
+
+ // Clear the measurement as on a retry started from main control the old values will be displayed
+ ClearRssiMeasurement();
+ // kick off RSSI test
+ StartRssiMeasurement();
+
+ // Exit if meanwhile cancellation is required
+ if (CancellationToken.IsCancellationRequested)
+ CancellationProcedure();
+
+ var exitTime = DateTime.Now + TimeSpan.FromSeconds(Timeout_s);
+ var actualTime = DateTime.Now;
+ // wait on result or timeout or stop request from main window
+ while (!_testFinished && exitTime > actualTime && SingleProcessState != SingleProcessState.Idle)
+ {
+ // Exit if meanwhile cancellation is required
+ if (CancellationToken.IsCancellationRequested)
+ CancellationProcedure();
+
+ Thread.Sleep(TimeoutLoop_ms);
+ actualTime = DateTime.Now;
+ ActualProcessProgress++;
+ }
+
+ // lock all buttons as process is finished
+ DisableAllButtons();
+ }// !skipRadioCheck
+
+ // reset all radio alarms
+ WriteRegisterLogAndProcessCtr(new ProgrammingParameters("SENSUSRADIO_MainAlarmMask",
+ new Byte[] { 0 }, ProgrammingSource.ProgramInternal));
+ WriteRegisterLogAndProcessCtr(new ProgrammingParameters("SENSUSRADIO_ExtendedAlarmMask",
+ new Byte[] { 0 }, ProgrammingSource.ProgramInternal));
+ // set system state back to shipping mode
+ WriteRegisterLogAndProcessCtr(new ProgrammingParameters("SENSUSRADIO_SystemState",
+ new Byte[] { 0xFF }, ProgrammingSource.ProgramInternal));
+ ActualProcessProgress++;
+
+ // check radio is in customer mode 0x02 and alarm masks are 0
+ var mainAlarmMask =
+ RegisterConverter.ByteArrayToValue(Meter.ReadRegister("SENSUSRADIO_MainAlarmMask"));
+ var extendedAlarmMask =
+ RegisterConverter.ByteArrayToValue(Meter.ReadRegister("SENSUSRADIO_ExtendedAlarmMask"));
+ _finalRadioSystemState = RegisterConverter.ByteArrayToValue(Meter.ReadRegister("SENSUSRADIO_SystemState"));
+ ActualProcessProgress++;
+
+ if (// Radio mode and alarm masks NOT okay forces always an error
+ // radio system state 0x02 shipping mode, 0x01 production mode, 0x0C transmission and data logger active
+ _finalRadioSystemState != 0x02 || mainAlarmMask != 0 || extendedAlarmMask != 0
+ // If radio check is enabled the signal level has to be in range and the test has to be finished
+ || (!skipRadioCheck && (!_successSignalLevel || !_sirtComOkay || !_testFinished)))
+ {
+ return SetTestFailed(!_sirtComOkay ? Resources.StrErrorMsgSirt : Resources.StrErrorMsgRadioCheck);
+ }
+
+ SuccessMsgDispatcher(Resources.StrSuccessMsgRadioInCustomerMode);
+ SuccessMsgDispatcher(Resources.StrSuccessMsgRadioAlarmsReset);
+
+ // Skip radio check by requirement
+ if (skipRadioCheck)
+ {
+ EolProgress.FinalRadioSystemStateCheck = EOLStatus.NA;
+ WarningMsgDispatcher(Resources.StrSkippedMsgRadioCheckSpecialPermission);
+ PrepareExit();
+ return StatusReturn.Skipped;
+ }
+ return SetTestSucceeded();
+
+ }
+ catch (Exception ex)
+ {
+ Meter?.WriteLog(ex.Message);
+ return SetTestFailed(Resources.StrErrorMsgRadioCheck);
+ }
+ }
+
+ ///
+ /// Common for test Init
+ ///
+ private void TestInit()
+ {
+ // Uncheck executed process to leave the result open needed for retries
+ EolProgress.RadioCheckId = null;
+ EolProgress.FinalRadioSystemState = null;
+ EolProgress.FinalRadioSystemStateCheck = null;
+ // Value not saved as test hasn't been executed
+ _radioResultCheckId = 0;
+ _finalRadioSystemState = 0;
+
+ _sirtComOkay = false;
+ _testFinished = false;
+ _successSignalLevel = false;
+ }
+
+ ///
+ /// Initialize the SIRT
+ ///
+ ///
+ private Boolean SirtInit()
+ {
+ try
+ {
+ // Reset needed for repeated run
+ _stateMachine?.Stop();
+ _stateMachine?.ClearBUPRadioAdresses();
+ _stateMachine?.ClearPam();
+ _stateMachine = null;
+ _dataContainer = null;
+ _stateMachine = new Statemashine();
+ _dataContainer = new DataContainer();
+
+ }
+ catch (Exception ex)
+ {
+ Meter?.WriteLog(ex.Message);
+ return false;
+ }
+
+ return true;
+ }
+
+
+ ///
+ /// Common to prepare exit for all status returns
+ ///
+ private void PrepareExit()
+ {
+ EolProgress.RadioCheckId = _radioResultCheckId;
+ EolProgress.FinalRadioSystemState = _finalRadioSystemState;
+
+ // Essential to logout from meter at any exit
+ Meter?.Logout();
+
+ _stateMachine?.Stop();
+ _stateMachine = null;
+ _dataContainer = null;
+ }
+
+ ///
+ /// Common for test failed
+ ///
+ /// error message to dispatch and log
+ ///
+ private StatusReturn SetTestFailed(String errorMsg)
+ {
+ EolProgress.FinalRadioSystemStateCheck = EOLStatus.FAIL;
+ ErrorMsgDispatcher(errorMsg);
+ PrepareExit();
+ return StatusReturn.Failed;
+ }
+
+ ///
+ /// Common for test succeeded
+ ///
+ ///
+ private StatusReturn SetTestSucceeded()
+ {
+ EolProgress.FinalRadioSystemStateCheck = EOLStatus.OK;
+ PrepareExit();
+ return StatusReturn.Okay;
+ }
+
+ ///
+ /// Disable all buttons of user control.
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ private void DisableAllButtons()
+ {
+ //EnableBtn(_checkRadioUserControl.btnSkip, false);
+ EnableBtn(_checkRadioUserControl.btnRetry, false);
+ }
+
+ private void EnableBtn(Button btn, Boolean enable)
+ {
+ btn.Dispatcher.Invoke(DispatcherPriority.Send,
+ new Action(() =>
+ {
+ btn.IsEnabled = enable;
+ }
+ ));
+ }
+
+ private void UpdateUc()
+ {
+ _checkRadioUserControl.SetUi(new UcRadioCheck.UiContainer(_rssiPamSirtDbMin, _rssiSemiCordonelDbMin,
+ _rssiPamSirtMeasuredByCordonel, _rssiSemiCordonelMeasuredBySirt, _rssiPamSirtDbMax, _rssiSemiCordonelDbMax));
+ }
+
+ ///
+ /// Check of radio signal strength.
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ private void StartRssiMeasurement()
+ {
+ // disable all buttons during ongoing measurement process
+ DisableAllButtons();
+ UpdateUc();
+
+ try
+ {
+ ActualProcessProgress++;
+ GetRssiMinMaxValuesFromDb(_sirtBoxNr, Meter.OrderNumber);
+ SendPamListenSemi((Int32)_radioAddressCordonel, _sirtComport, _radioEncryptionKey);
+ UpdateUc();
+ ActualProcessProgress++;
+ }
+ catch (Exception ex)
+ {
+ _testFinished = true;
+ Meter?.WriteLog(ex.Message);
+ LogNewStatusMsg(Resources.StrErrorMsgRadioCheck);
+ }
+ }
+
+ ///
+ /// Clear RSSI values for display of unknown values but leave limits active as
+ /// those are already loaded from DB and will not change during retry. Therefore,
+ /// the process can be optimized to avoid recurrent DB access!
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ private void ClearRssiMeasurement()
+ {
+ _sirtComOkay = false;
+ _rssiPamSirtMeasuredByCordonel = null;
+ _rssiSemiCordonelMeasuredBySirt = null;
+ }
+
+ ///
+ /// Retry collection of RSSI values (entire process with sending PAM and receiving SEMI).
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ private void Retry()
+ {
+ // reset process counter to start from scratch
+ ActualProcessProgress = 0;
+ if (_stateMachine != null)
+ {
+ _stateMachine.ClearPam();
+ _stateMachine.Stop();
+ }
+ ClearRssiMeasurement();
+ UpdateUc();
+ SendPamListenSemi((Int32)_radioAddressCordonel, _sirtComport, _radioEncryptionKey);
+ }
+
+ ///
+ /// ATTENTION:
+ /// As those definitions are directly used as DB definitions for pushing the result:
+ ///
+ /// LEAVE THOSE NAMING AS DEFINED HERE!
+ ///
+ ///
+ private class DataContainer
+ {
+ public Int32 RadioAdress
+ {
+ get; set;
+ }
+ public Byte RSSI_PAM
+ {
+ get; set;
+ }
+ public Byte RSSI_SEMI
+ {
+ get; set;
+ }
+ public Int32 LimitId
+ {
+ get; set;
+ }
+ public Byte Result
+ {
+ get; set;
+ }
+ }
+
+
+ ///
+ /// Save RSSI values to DB.
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ private void SaveRssiLevelsToDb()
+ {
+ try
+ {
+ if (_dataContainer != null)
+ {
+ _dataContainer.RadioAdress = (Int32)_radioAddressCordonel; // 0-4294967295
+ var url = $"{ServiceUrls.GenesisRadioCheckServiceUrl()}SaveRSSI";
+
+ var response = LocalWebRequest.PostRequestAsync(url, 30000, out var httpStatus, _dataContainer);
+ if (!string.IsNullOrEmpty(response) && httpStatus == HttpStatusCode.OK)
+ {
+ var jsonObj = JObject.Parse(response);
+ _radioResultCheckId = Convert.ToInt32(jsonObj.SelectToken("radiocheckid"));
+ }
+
+ SuccessMsgDispatcher(Resources.StrSuccessMsgSetRadioRssiLimitsToDb);
+ ActualProcessProgress++;
+ }
+ else
+ {
+ ErrorMsgDispatcher(Resources.StrErrorMsgSetRadioRssiLimitsToDb);
+ }
+ }
+ catch (Exception ex)
+ {
+ Meter?.WriteLog(ex.Message);
+ ErrorMsgDispatcher(Resources.StrErrorMsgSetRadioRssiLimitsToDb);
+ }
+ finally
+ {
+ _testFinished = true;
+ }
+ }
+
+ ///
+ /// Get RSSI values from DB.
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ private void GetRssiMinMaxValuesFromDb(Byte BoxNr, Int32 productionOrderNo)
+ {
+ try
+ {
+ if (_dataContainer != null)
+ {
+ var url = $"{ServiceUrls.GenesisRadioCheckServiceUrl()}GetLimits/{BoxNr}/{productionOrderNo}";
+ var body = LocalWebRequest.GetRequest(url, 300000, out var httpStatus);
+ if (httpStatus != HttpStatusCode.OK || string.IsNullOrEmpty(body))
+ {
+ ErrorMsgDispatcher(Resources.StrErrorMsgGetRadioRssiLimitsFromDb);
+ return;
+ }
+ var o = JObject.Parse(body);
+
+ _dataContainer.LimitId = Convert.ToInt32(o.SelectToken("LimitId")?.ToString());
+ _rssiPamSirtDbMin = Convert.ToByte(o.SelectToken("RSSI_PAM_Min")?.ToString());
+ _rssiPamSirtDbMax = Convert.ToByte(o.SelectToken("RSSI_PAM_Max")?.ToString());
+ _rssiSemiCordonelDbMin = Convert.ToByte(o.SelectToken("RSSI_SEMI_Min")?.ToString());
+ _rssiSemiCordonelDbMax = Convert.ToByte(o.SelectToken("RSSI_SEMI_Max")?.ToString());
+ SuccessMsgDispatcher(Resources.StrSuccessMsgGetRadioRssiLimitsFromDb +
+ $": ID: ({_dataContainer.LimitId}), " +
+ $"SIRT Min: ({_rssiPamSirtDbMin}), " +
+ $"SIRT Max: ({_rssiPamSirtDbMax}), " +
+ $"Cordonel Min: ({_rssiSemiCordonelDbMin}), " +
+ $"Cordonel Max: ({_rssiSemiCordonelDbMax})");
+ ActualProcessProgress++;
+ }
+ }
+ catch (Exception ex)
+ {
+ Meter?.WriteLog(ex.Message);
+ ErrorMsgDispatcher(Resources.StrErrorMsgGetRadioRssiLimitsFromDb);
+ }
+ }
+
+ ///
+ /// Send PAM to force a BUP and a SEMI and start the RSSI observer to measure the signal strength.
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ ///
+ /// - Optimized based on new documentations.
+ ///
+ private void SendPamListenSemi(Int32 radioAddress, Int32 byteComPort, String strKey)
+ {
+ if (_dataContainer == null || _stateMachine == null)
+ return;
+
+ _rssiPamSirtMeasuredByCordonel = null;
+ _rssiSemiCordonelMeasuredBySirt = null;
+
+ Byte P81_1 = 0;
+
+ _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);
+
+ LogNewStatusMsg($"{Resources.StrRadioMsgSendPam}: {radioAddress.ToString()}");
+
+ // Initialize the state machine of the SIRT dll
+ _stateMachine.Stop();
+ _stateMachine.ClearPam();
+ _stateMachine.Timeout_s = 30;
+
+ // Dummy PAM 00 with radio encryption key, SIRT dll takes the key for the response and the
+ // address for the request and response, CommandHex 00 is data size of 0, so it makes no sense
+ // to encrypt the 00 PAM, but the key will be used in the SEMI response
+ _stateMachine.SendPAM(radioAddress.ToString(), "00", "", P81_1, 1, 0, strKey, "0", true);
+ ActualProcessProgress++;
+
+ // SystemState 0x55 will force meter immediately to send BUP, internal the system state remains
+ // on 0x02. This has to be sent after PAM!
+ Meter.WriteRegister("SENSUSRADIO_SystemState", 0x55);
+
+ // Start polling
+ _stateMachine.OnStateChanged += StateMachineOnStateChange_Handler;
+ _stateMachine.Start();
+
+ ActualProcessProgress++;
+ }
+
+ ///
+ /// Get RSSI (Received Signal Strength Indicator) values from SIRT (Sensus Interface Radio Tool).
+ /// Set the
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ ///
+ /// - Initial
+ ///
+ private void GotRssiCallback(Byte rssiSemiCordonel, Byte rssiPamSirt)
+ {
+ if (_dataContainer == null)
+ return;
+
+ // RSSI PAM sent by SIRT and measured by Cordonel
+ LogNewStatusMsg($"{Resources.StrMeasuredMsgRadioRssiSirt}: ({rssiPamSirt})");
+ // RSSI SEMI sent by Cordonel and measured by SIRT
+ LogNewStatusMsg($"{Resources.StrMeasuredMsgRadioRssiCordonel}: ({rssiSemiCordonel})");
+
+ _rssiPamSirtMeasuredByCordonel = rssiPamSirt;
+ _rssiSemiCordonelMeasuredBySirt = rssiSemiCordonel;
+ _dataContainer.RSSI_PAM = rssiPamSirt;
+ _dataContainer.RSSI_SEMI = rssiSemiCordonel;
+
+ UpdateUc();
+
+ // threshold check for failed test
+ if (_rssiPamSirtMeasuredByCordonel < _rssiPamSirtDbMin ||
+ _rssiPamSirtMeasuredByCordonel > _rssiPamSirtDbMax ||
+ _rssiSemiCordonelMeasuredBySirt < _rssiSemiCordonelDbMin ||
+ _rssiSemiCordonelMeasuredBySirt > _rssiSemiCordonelDbMax)
+ {
+ _dataContainer.Result = 0;
+ // done can finish the test which is equal to abort on error
+ //EnableBtn(_checkRadioUserControl.btnSkip, true);
+ // reset can repeat the test as often as wanted
+ EnableBtn(_checkRadioUserControl.btnRetry, true);
+ _successSignalLevel = false;
+ }
+ else
+ {
+ // on success there is no choice to made, it is finished
+ _dataContainer.Result = 1;
+ _successSignalLevel = true;
+
+ // safe those results to DB for logging
+ SaveRssiLevelsToDb();
+ }
+ }
+
+ ///
+ /// State machine state change handler.
+ ///
+ ///
+ ///
+ /// - Initial
+ ///
+ private void StateMachineOnStateChange_Handler(Object sender, MyEventArgs e)
+ {
+ if (_stateMachine == null)
+ return;
+ try
+ {
+ // Reading back sent PAM from SIRT to Cordonel
+ var pam = _stateMachine.GetPAM(1);
+
+ if (pam != null)
+ {
+ if (pam.State == PAM.PAMStates.Timeout)
+ {
+ LogNewStatusMsg($"Timeout {pam.GetTime()} s");
+ }
+
+ if (pam.CountSemi > 0)
+ {
+ // SEMI received from Cordonel
+ _stateMachine.Stop();
+ _stateMachine.ClearPam();
+
+ var hexBytesSemi = pam.Semi.HexData.Replace(" ", "");
+ var semiBytes = new Byte[hexBytesSemi.Length / 2];
+
+ for (var i = 0; i < hexBytesSemi.Length; i += 2)
+ semiBytes[i / 2] = Convert.ToByte(hexBytesSemi.Substring(i, 2), 16);
+
+ // SEMI Status okay if 0, if SIRT dll returns unequal to 0 the encryption key is wrong
+ // If 0 the encryption key is correct
+ if (semiBytes[19] == 0)
+ {
+ // RSSI SEMI sent by Cordonel and measured by SIRT (signal level of Cordonel in byte 2)
+ var rssiSemiMeasuredBySirt = semiBytes[2];
+
+ // RSSI PAM sent by SIRT and measured by Cordonel (signal level of SIRT packet to SEMI in byte 20)
+ var rssiPamMeasuredByCordonel = semiBytes[20];
+
+ GotRssiCallback(rssiSemiMeasuredBySirt, rssiPamMeasuredByCordonel);
+ _sirtComOkay = true;
+ }
+ else
+ {
+ // SEMI Status not 0 is internal error which should be logged
+ LogNewStatusMsg(pam.Semi.GetPamErrorMessage());
+ _sirtComOkay = false;
+ }
+ }
+ else
+ {
+ LogNewStatusMsg($"BUPS: ({pam.CountBup})");
+ _sirtComOkay = false;
+ }
+ }//pam not null
+ else
+ {
+ _stateMachine.Stop();
+ _stateMachine.ClearPam();
+ }
+ }
+ catch (Exception ex)
+ {
+ Meter?.WriteLog(ex.Message);
+ }
+ }
+ }
+}
diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/IProcessStateDef.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/IProcessStateDef.cs
index c5022e48..9fa7f526 100644
--- a/Common/Production/ProductionUiCordonel/ProductionProcesses/IProcessStateDef.cs
+++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/IProcessStateDef.cs
@@ -99,6 +99,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
///
/// - Changed to sorted list by production process number
///
- List GetAllEolRelevantProcesses();
+ List GetAllProductionProcesses();
}
}
diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/ProcessController.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/ProcessController.cs
index ad66190a..5ff2e2e4 100644
--- a/Common/Production/ProductionUiCordonel/ProductionProcesses/ProcessController.cs
+++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/ProcessController.cs
@@ -605,7 +605,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses
Processes = new List();
// get all processes relevant for EOL from table which has to be sorted
- var processes = _processStateDef.GetAllEolRelevantProcesses();
+ var processes = _processStateDef.GetAllProductionProcesses();
foreach (var process in processes)
{
diff --git a/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj b/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj
index 33c0554b..aacaff13 100644
--- a/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj
+++ b/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj
@@ -370,11 +370,7 @@
Designer
MSBuild:Compile
-<<<<<<< HEAD
-
-=======
->>>>>>> Dev_Picking
Designer
MSBuild:Compile
diff --git a/Common/Production/ProductionUiCordonel/ProductionWindow.xaml.cs b/Common/Production/ProductionUiCordonel/ProductionWindow.xaml.cs
index 774a2546..493733e2 100644
--- a/Common/Production/ProductionUiCordonel/ProductionWindow.xaml.cs
+++ b/Common/Production/ProductionUiCordonel/ProductionWindow.xaml.cs
@@ -21,7 +21,6 @@ using Xylem.Common.CommonCore.Consts;
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses;
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
-using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses;
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EventArgs;
using Xylem.Common.Utils.Logging;
using Xylem.Common.Utils.UserAccessCtrl;