Merge branch 'omni_test' into dev_spzvtbg

This commit is contained in:
Stoyan Zlatev
2024-02-06 11:03:54 +01:00
203 changed files with 16477 additions and 3798 deletions
+1 -1
View File
@@ -155,7 +155,7 @@
</site>
<site name="MeterProcessState" id="2">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="D:\Projekte\SENSUS_GitLab\laa_production\Common\Service\MeterProcessState" />
<virtualDirectory path="/" physicalPath="C:\Users\SZLATEV\source\repos\laa_production\Common\Service\MeterProcessState" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:56011:localhost" />
+265 -475
View File
@@ -27,10 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPackages", "Hardware\Wa
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Shared", ".Shared", "{26EB462B-1FAC-4CEA-A9B9-DB96CA9CC864}"
ProjectSection(SolutionItems) = preProject
..\.gitignore = ..\.gitignore
Hardware\WaterMeter\Genesis\GenesisCore\configuration.json = Hardware\WaterMeter\Genesis\GenesisCore\configuration.json
.shared\NlogConfig.xml = .shared\NlogConfig.xml
..\ReSharperSettings\ReSharperSettings.DotSettings = ..\ReSharperSettings\ReSharperSettings.DotSettings
.shared\SharedAssemblyInfo.cs = .shared\SharedAssemblyInfo.cs
.shared\status.json = .shared\status.json
EndProjectSection
@@ -173,31 +171,21 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPackages", "Hardware\Wa
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProtocolCore", "Hardware\Interfaces\Protocols\ProtocolCore\ProtocolCore.csproj", "{8BDD2789-96D4-43EA-AAD7-0F49D0347998}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SIRTBroadcaster.UI", "SIRTBroadcaster.UI\SIRTBroadcaster.UI.csproj", "{2550B77D-D975-4A50-9C6A-526D4E07754D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SIRTBroadcaster.Abstraction", "SIRTBroadcaster.Abstraction\SIRTBroadcaster.Abstraction.csproj", "{C27BA66C-C3A7-48A2-A644-CBA77E28E531}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SIRTBroadcaster.Client", "SIRTBroadcaster.Client\SIRTBroadcaster.Client.csproj", "{4221F992-599E-498C-A409-6D1E70E0A6F9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SIRT", "SIRT", "{AF973E0E-2B44-4F1A-B1E7-77C8B4F30579}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SIRTBroadcaster.Host", "SIRTBroadcaster.Host\SIRTBroadcaster.Host.csproj", "{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LaaProduction", "LaaProduction\LaaProduction.csproj", "{FD30EB7A-7809-4E62-9374-791D31877D6D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonConsole", "CommonConsole\CommonConsole.csproj", "{AFC428F5-0141-4A3F-BEF2-470A89D972F6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "modbus_master_csharp", "modbus_master_csharp\modbus_master_csharp.csproj", "{F14940F8-3C86-4BB7-A915-B021E4B3052D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "eRegister", "eRegister", "{FBF162DF-A4C6-41D1-9324-5517C13C658B}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OmniPlus", "OmniPlus", "{68323534-4337-4E3A-89BC-11D8BB55343A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Protocols", "Protocols", "{1B519B0D-5E1C-4400-A8CE-F7B3CC045745}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExchangeHub", "OmniPlus\ExchangeHub\ExchangeHub.csproj", "{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamingProtocol", "Hardware\WaterMeter\eRegister\Protocols\StreamingProtocol.csproj", "{B6A19B80-0F0F-434C-A754-A7712FC208B2}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmniPlus", "OmniPlus\OmniPlus\OmniPlus.csproj", "{F8D84B9A-0FCF-4083-B067-8C39B7314152}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPackages", "Hardware\WaterMeter\eRegister\DataPackages\DataPackages.csproj", "{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlExtensions", "OmniPlus\SqlExtensions\SqlExtensions.csproj", "{B8523894-2C40-4FF0-A399-B7A91FAE45EA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eRegisterCore", "Hardware\WaterMeter\eRegister\eRegisterCore\eRegisterCore.csproj", "{A83696BF-D8A2-4809-8424-CFE172AED5B6}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InspectionUI", "OmniPlus\InspectionUI\InspectionUI.csproj", "{01A28A70-D5E6-4898-8C22-E64400A3B80F}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
@@ -3945,262 +3933,6 @@ Global
{8BDD2789-96D4-43EA-AAD7-0F49D0347998}.XP32bit|x64.Build.0 = XP32bit|x64
{8BDD2789-96D4-43EA-AAD7-0F49D0347998}.XP32bit|x86.ActiveCfg = XP32bit|x86
{8BDD2789-96D4-43EA-AAD7-0F49D0347998}.XP32bit|x86.Build.0 = XP32bit|x86
{2550B77D-D975-4A50-9C6A-526D4E07754D}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.COM|Any CPU.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.COM|Any CPU.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.COM|x64.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.COM|x64.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.COM|x86.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.COM|x86.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Debug|x64.ActiveCfg = Debug|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Debug|x64.Build.0 = Debug|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Debug|x86.ActiveCfg = Debug|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Debug|x86.Build.0 = Debug|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.PerformTest|x64.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.PerformTest|x64.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.PerformTest|x86.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.PerformTest|x86.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Release|Any CPU.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Release|x64.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Release|x64.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Release|x86.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.Release|x86.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.ReleaseTest|x64.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.ReleaseTest|x86.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.XP32bit|x64.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.XP32bit|x64.Build.0 = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.XP32bit|x86.ActiveCfg = Release|Any CPU
{2550B77D-D975-4A50-9C6A-526D4E07754D}.XP32bit|x86.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.COM|Any CPU.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.COM|Any CPU.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.COM|x64.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.COM|x64.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.COM|x86.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.COM|x86.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Debug|x64.ActiveCfg = Debug|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Debug|x64.Build.0 = Debug|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Debug|x86.ActiveCfg = Debug|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Debug|x86.Build.0 = Debug|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.PerformTest|x64.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.PerformTest|x64.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.PerformTest|x86.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.PerformTest|x86.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Release|Any CPU.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Release|x64.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Release|x64.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Release|x86.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.Release|x86.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.ReleaseTest|x64.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.ReleaseTest|x86.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.XP32bit|x64.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.XP32bit|x64.Build.0 = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.XP32bit|x86.ActiveCfg = Release|Any CPU
{C27BA66C-C3A7-48A2-A644-CBA77E28E531}.XP32bit|x86.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.COM|Any CPU.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.COM|Any CPU.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.COM|x64.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.COM|x64.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.COM|x86.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.COM|x86.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Debug|x64.ActiveCfg = Debug|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Debug|x64.Build.0 = Debug|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Debug|x86.ActiveCfg = Debug|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Debug|x86.Build.0 = Debug|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.PerformTest|x64.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.PerformTest|x64.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.PerformTest|x86.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.PerformTest|x86.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Release|Any CPU.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Release|x64.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Release|x64.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Release|x86.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.Release|x86.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.ReleaseTest|x64.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.ReleaseTest|x86.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.XP32bit|x64.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.XP32bit|x64.Build.0 = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.XP32bit|x86.ActiveCfg = Release|Any CPU
{4221F992-599E-498C-A409-6D1E70E0A6F9}.XP32bit|x86.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.COM|Any CPU.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.COM|Any CPU.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.COM|x64.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.COM|x64.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.COM|x86.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.COM|x86.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Debug|x64.ActiveCfg = Debug|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Debug|x64.Build.0 = Debug|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Debug|x86.ActiveCfg = Debug|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Debug|x86.Build.0 = Debug|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.PerformTest|x64.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.PerformTest|x64.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.PerformTest|x86.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.PerformTest|x86.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Release|Any CPU.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Release|x64.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Release|x64.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Release|x86.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.Release|x86.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.ReleaseTest|x64.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.ReleaseTest|x86.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.XP32bit|x64.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.XP32bit|x64.Build.0 = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.XP32bit|x86.ActiveCfg = Release|Any CPU
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}.XP32bit|x86.Build.0 = Release|Any CPU
{FD30EB7A-7809-4E62-9374-791D31877D6D}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{FD30EB7A-7809-4E62-9374-791D31877D6D}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{FD30EB7A-7809-4E62-9374-791D31877D6D}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
@@ -4393,198 +4125,262 @@ Global
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x86.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.COM|Any CPU.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.COM|Any CPU.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.COM|x64.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.COM|x64.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.COM|x86.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.COM|x86.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Debug|x64.ActiveCfg = Debug|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Debug|x64.Build.0 = Debug|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Debug|x86.ActiveCfg = Debug|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Debug|x86.Build.0 = Debug|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.PerformTest|x64.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.PerformTest|x64.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.PerformTest|x86.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.PerformTest|x86.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Release|Any CPU.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Release|x64.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Release|x64.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Release|x86.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.Release|x86.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.ReleaseTest|x64.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.ReleaseTest|x86.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.XP32bit|x64.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.XP32bit|x64.Build.0 = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.XP32bit|x86.ActiveCfg = Release|Any CPU
{B6A19B80-0F0F-434C-A754-A7712FC208B2}.XP32bit|x86.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.COM|Any CPU.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.COM|Any CPU.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.COM|x64.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.COM|x64.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.COM|x86.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.COM|x86.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Debug|x64.ActiveCfg = Debug|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Debug|x64.Build.0 = Debug|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Debug|x86.ActiveCfg = Debug|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Debug|x86.Build.0 = Debug|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.PerformTest|x64.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.PerformTest|x64.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.PerformTest|x86.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.PerformTest|x86.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Release|Any CPU.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Release|x64.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Release|x64.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Release|x86.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.Release|x86.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.ReleaseTest|x64.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.ReleaseTest|x86.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.XP32bit|x64.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.XP32bit|x64.Build.0 = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.XP32bit|x86.ActiveCfg = Release|Any CPU
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478}.XP32bit|x86.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.COM|Any CPU.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.COM|Any CPU.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.COM|x64.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.COM|x64.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.COM|x86.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.COM|x86.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Debug|x64.ActiveCfg = Debug|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Debug|x64.Build.0 = Debug|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Debug|x86.ActiveCfg = Debug|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Debug|x86.Build.0 = Debug|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.PerformTest|x64.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.PerformTest|x64.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.PerformTest|x86.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.PerformTest|x86.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Release|Any CPU.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Release|x64.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Release|x64.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Release|x86.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.Release|x86.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.ReleaseTest|x64.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.ReleaseTest|x86.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.XP32bit|x64.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.XP32bit|x64.Build.0 = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.XP32bit|x86.ActiveCfg = Release|Any CPU
{A83696BF-D8A2-4809-8424-CFE172AED5B6}.XP32bit|x86.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.COM|Any CPU.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.COM|Any CPU.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.COM|x64.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.COM|x64.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.COM|x86.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.COM|x86.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Debug|x64.ActiveCfg = Debug|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Debug|x64.Build.0 = Debug|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Debug|x86.ActiveCfg = Debug|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Debug|x86.Build.0 = Debug|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.PerformTest|x64.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.PerformTest|x64.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.PerformTest|x86.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.PerformTest|x86.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Release|Any CPU.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Release|x64.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Release|x64.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Release|x86.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.Release|x86.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.ReleaseTest|x64.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.ReleaseTest|x86.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.XP32bit|x64.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.XP32bit|x64.Build.0 = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.XP32bit|x86.ActiveCfg = Release|Any CPU
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}.XP32bit|x86.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.COM|Any CPU.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.COM|Any CPU.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.COM|x64.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.COM|x64.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.COM|x86.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.COM|x86.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Debug|x64.ActiveCfg = Debug|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Debug|x64.Build.0 = Debug|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Debug|x86.ActiveCfg = Debug|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Debug|x86.Build.0 = Debug|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.PerformTest|x64.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.PerformTest|x64.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.PerformTest|x86.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.PerformTest|x86.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Release|Any CPU.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Release|x64.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Release|x64.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Release|x86.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.Release|x86.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.ReleaseTest|x64.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.ReleaseTest|x86.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.XP32bit|x64.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.XP32bit|x64.Build.0 = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.XP32bit|x86.ActiveCfg = Release|Any CPU
{F8D84B9A-0FCF-4083-B067-8C39B7314152}.XP32bit|x86.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.COM|Any CPU.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.COM|Any CPU.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.COM|x64.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.COM|x64.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.COM|x86.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.COM|x86.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Debug|x64.ActiveCfg = Debug|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Debug|x64.Build.0 = Debug|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Debug|x86.ActiveCfg = Debug|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Debug|x86.Build.0 = Debug|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.PerformTest|x64.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.PerformTest|x64.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.PerformTest|x86.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.PerformTest|x86.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Release|Any CPU.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Release|x64.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Release|x64.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Release|x86.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.Release|x86.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.ReleaseTest|x64.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.ReleaseTest|x86.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.XP32bit|x64.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.XP32bit|x64.Build.0 = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.XP32bit|x86.ActiveCfg = Release|Any CPU
{B8523894-2C40-4FF0-A399-B7A91FAE45EA}.XP32bit|x86.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.COM|Any CPU.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.COM|Any CPU.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.COM|x64.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.COM|x64.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.COM|x86.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.COM|x86.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Debug|x64.ActiveCfg = Debug|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Debug|x64.Build.0 = Debug|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Debug|x86.ActiveCfg = Debug|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Debug|x86.Build.0 = Debug|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.PerformTest|x64.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.PerformTest|x64.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.PerformTest|x86.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.PerformTest|x86.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Release|Any CPU.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Release|x64.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Release|x64.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Release|x86.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.Release|x86.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.ReleaseTest|x64.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.ReleaseTest|x86.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.XP32bit|x64.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.XP32bit|x64.Build.0 = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.XP32bit|x86.ActiveCfg = Release|Any CPU
{01A28A70-D5E6-4898-8C22-E64400A3B80F}.XP32bit|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -4662,19 +4458,13 @@ Global
{D6B81C60-2763-4C4D-989F-90822F53B01A} = {94579693-7AC6-4FF0-B540-1F3780E1BCFA}
{BA17D20E-0CEB-4B27-9772-2392BD750ED5} = {C9393A97-C0BB-4D59-A879-B572BE04CE15}
{8BDD2789-96D4-43EA-AAD7-0F49D0347998} = {EC10DAFE-88CF-42D5-99E7-D247938B6430}
{2550B77D-D975-4A50-9C6A-526D4E07754D} = {03D4F23E-7E4A-4091-BC96-036C996D351A}
{C27BA66C-C3A7-48A2-A644-CBA77E28E531} = {AF973E0E-2B44-4F1A-B1E7-77C8B4F30579}
{4221F992-599E-498C-A409-6D1E70E0A6F9} = {AF973E0E-2B44-4F1A-B1E7-77C8B4F30579}
{AF973E0E-2B44-4F1A-B1E7-77C8B4F30579} = {99B23EE9-CE50-4924-A055-C39EFA038721}
{A9D1A99D-6E55-4394-86AD-B5C53E9225EB} = {AF973E0E-2B44-4F1A-B1E7-77C8B4F30579}
{FD30EB7A-7809-4E62-9374-791D31877D6D} = {696A94BE-7237-4AE2-9E36-6059DE519971}
{AFC428F5-0141-4A3F-BEF2-470A89D972F6} = {C17363DF-A043-4F25-8EBA-2B3B078227DC}
{F14940F8-3C86-4BB7-A915-B021E4B3052D} = {B4F8545B-F379-42A5-BDE9-763FD7B79598}
{FBF162DF-A4C6-41D1-9324-5517C13C658B} = {5563DD3B-2287-4BED-97BF-F0389FF505AF}
{1B519B0D-5E1C-4400-A8CE-F7B3CC045745} = {FBF162DF-A4C6-41D1-9324-5517C13C658B}
{B6A19B80-0F0F-434C-A754-A7712FC208B2} = {1B519B0D-5E1C-4400-A8CE-F7B3CC045745}
{C2808A8E-C0BA-44EC-B7B1-1C66AD3D8478} = {FBF162DF-A4C6-41D1-9324-5517C13C658B}
{A83696BF-D8A2-4809-8424-CFE172AED5B6} = {FBF162DF-A4C6-41D1-9324-5517C13C658B}
{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D} = {68323534-4337-4E3A-89BC-11D8BB55343A}
{F8D84B9A-0FCF-4083-B067-8C39B7314152} = {68323534-4337-4E3A-89BC-11D8BB55343A}
{B8523894-2C40-4FF0-A399-B7A91FAE45EA} = {68323534-4337-4E3A-89BC-11D8BB55343A}
{01A28A70-D5E6-4898-8C22-E64400A3B80F} = {68323534-4337-4E3A-89BC-11D8BB55343A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4BCB7B69-696C-436A-86F7-C91EA5588164}
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
</configuration>
+20 -19
View File
@@ -8,10 +8,11 @@
<OutputType>Exe</OutputType>
<RootNamespace>CommonConsole</RootNamespace>
<AssemblyName>CommonConsole</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -33,40 +34,40 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ProgramLogFileHelper.cs" />
<Compile Include="FactoryUnseal.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReflectionExtensions.cs" />
<Compile Include="ServiceProvider.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
<ProjectReference Include="..\OmniPlus\ExchangeHub\ExchangeHub.csproj">
<Project>{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}</Project>
<Name>ExchangeHub</Name>
</ProjectReference>
<ProjectReference Include="..\OmniPlus\OmniPlus\OmniPlus.csproj">
<Project>{F8D84B9A-0FCF-4083-B067-8C39B7314152}</Project>
<Name>OmniPlus</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Logic\ServiceCore\ServiceCore.csproj">
<Project>{F7E3DF42-4D35-4A0C-9182-90438F9956E1}</Project>
<Name>ServiceCore</Name>
</ProjectReference>
<ProjectReference Include="..\Service\MeterProcessState\MeterProcessState.csproj">
<Project>{1057AD21-BA22-4CAB-B3FE-88C5C9980E6A}</Project>
<Name>MeterProcessState</Name>
</ProjectReference>
<ProjectReference Include="..\Utils\ByteArrayStyle\ByteArrayStyle.csproj">
<Project>{8A619CD5-6C8D-420C-A132-7946C6F13E6E}</Project>
<Name>ByteArrayStyle</Name>
</ProjectReference>
<None Include="app.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+306
View File
@@ -0,0 +1,306 @@
namespace CommonConsole
{
using OmniPlus;
using System;
using System.Linq;
using System.Text;
public static class OmniExtensions
{
public static void FactoryUnseal(OmniUniProConnection connection)
{
var _sealed = connection.Send(0xFD, 0x63)[1] == 1;
Console.WriteLine($"--- Sealed: {connection.Send(0xFD, 0x63)[1] == 1}");
Console.WriteLine($"--- Version & Type: {Encoding.ASCII.GetString(connection.Send(0x05))}");
Console.WriteLine("----------------------------------------------------------------------");
Console.WriteLine("--- 0. Test parameters:");
Console.WriteLine("--- SSSS: 1");
Console.WriteLine("--- IIII: 2");
Console.WriteLine("--- CCCC: 3");
Console.WriteLine("--- CCCC: 4");
Console.WriteLine("--- Command: FD 64 00 SS SS II II CC CC VV VV (Hash is BE)");
Console.WriteLine("--- : FD 64 00 each part is LE except the last one");
Console.WriteLine("--- 1.0 According docs: FD 64 00 01 00 02 00 03 00 00 04 (Hash is BE)");
Console.WriteLine("--- 1.1 According docs: FD 64 00 04 00 00 03 00 02 00 01 (Hash is LE)");
Console.WriteLine("--- 2.0 When all LE: FD 64 00 01 00 02 00 03 00 04 00 (Hash is BE)");
Console.WriteLine("--- 2.1 When all LE: FD 64 00 00 04 00 03 00 02 00 01 (Hash is LE)");
Console.WriteLine("--- 3.0 When all BE: FD 64 00 00 01 00 02 00 03 00 04 (Hash is BE)");
Console.WriteLine("--- 3.1 When all BE: FD 64 00 04 00 03 00 02 00 01 00 (Hash is LE)");
Console.WriteLine("----------------------------------------------------------------------");
if (_sealed)
{
//____________________0_____1_____2_____3_____4_____5_____6_____7_____8_____9____10__
//_____________________________________SS____SS____II____II____CC____CC____VV____VV__
byte[] request = new byte[] { 0xFD, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Console.WriteLine("--- 1.0 According docs: hash is sent BE");
Console.WriteLine("----------------------------------------------------------------------");
byte[] hash = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// Test case 1 - according documentation - hash BE
connection.Calculate_IIII_LE().CopyTo(hash, 2);
connection.Calculate_CCCC_LE().CopyTo(hash, 4);
connection.Calculate_VVVV_LE().CopyTo(hash, 6);
connection.Calculate_SSSS_LE().CopyTo(hash, 0); // .Reverse().ToArray()
Array.Copy(hash, 0, request, 3, 8);
connection.Send(request);
}
//Console.WriteLine("----------------------------------------------------------------------");
//Console.WriteLine("--- 1.1 According docs: hash is sent LE");
//Console.WriteLine("----------------------------------------------------------------------");
//hash = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
//// Test case 1 - according documentation - hash LE
//connection.Calculate_IIII_LE().CopyTo(hash, 2);
//connection.Calculate_CCCC_LE().CopyTo(hash, 4);
//connection.Calculate_VVVV_LE().CopyTo(hash, 6);
//connection.Calculate_SSSS_LE().Reverse().ToArray().CopyTo(hash, 0);
//Array.Copy(hash.Reverse().ToArray(), 0, request, 3, 8);
//connection.Send(request);
//Console.WriteLine("----------------------------------------------------------------------");
//Console.WriteLine("--- 2.0 When all LE: hash is sent BE");
//Console.WriteLine("----------------------------------------------------------------------");
//hash = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
//// Test case 2 all Little endian - hash BE
//connection.Calculate_IIII_LE().CopyTo(hash, 2);
//connection.Calculate_CCCC_LE().CopyTo(hash, 4);
//connection.Calculate_VVVV_LE().CopyTo(hash, 6);
//connection.Calculate_SSSS_LE().CopyTo(hash, 0);
//Array.Copy(hash, 0, request, 3, 8);
//connection.Send(request);
//Console.WriteLine("----------------------------------------------------------------------");
//Console.WriteLine("--- 2.1 When all LE: hash is sent LE");
//Console.WriteLine("----------------------------------------------------------------------");
//hash = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
//// Test case 2 all Little endian - hash LE
//connection.Calculate_IIII_LE().CopyTo(hash, 2);
//connection.Calculate_CCCC_LE().CopyTo(hash, 4);
//connection.Calculate_VVVV_LE().CopyTo(hash, 6);
//connection.Calculate_SSSS_LE().CopyTo(hash, 0);
//Array.Copy(hash.Reverse().ToArray(), 0, request, 3, 8);
//connection.Send(request);
//Console.WriteLine("----------------------------------------------------------------------");
//Console.WriteLine("--- 3.0 When all BE: hash is sent BE");
//Console.WriteLine("----------------------------------------------------------------------");
//hash = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
//// Test case 3 all Big endian - hash BE
//connection.Calculate_IIII_LE().Reverse().ToArray().CopyTo(hash, 2);
//connection.Calculate_CCCC_LE().Reverse().ToArray().CopyTo(hash, 4);
//connection.Calculate_VVVV_LE().Reverse().ToArray().CopyTo(hash, 6);
//connection.Calculate_SSSS_LE().Reverse().ToArray().CopyTo(hash, 0);
//Array.Copy(hash, 0, request, 3, 8);
//connection.Send(request);
//Console.WriteLine("----------------------------------------------------------------------");
//Console.WriteLine("--- 3.1 When all BE: hash is sent LE");
//Console.WriteLine("----------------------------------------------------------------------");
//hash = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
//// Test case 3 all Big endian - hash BE
//connection.Calculate_IIII_LE().Reverse().ToArray().CopyTo(hash, 2);
//connection.Calculate_CCCC_LE().Reverse().ToArray().CopyTo(hash, 4);
//connection.Calculate_VVVV_LE().Reverse().ToArray().CopyTo(hash, 6);
//connection.Calculate_SSSS_LE().Reverse().ToArray().CopyTo(hash, 0);
//Array.Copy(hash.Reverse().ToArray(), 0, request, 3, 8);
//connection.Send(request);
Console.WriteLine("----------------------------------------------------------------------");
Console.WriteLine($"--- Sealed: {connection.Send(0xFD, 0x63)[1] == 1}");
}
static byte[] Calculate_SSSS_LE(this OmniUniProConnection connection)
{
// response with status byte at the start
byte[] response = connection.Send(0xFD, 0x3D);
ushort result = 0;
if (response[0] == 0x01)
{
// returns uint32 from 4 little endian bytes
uint seconds = BitConverter.ToUInt32(response, 1);
Console.WriteLine($"--- Seconds active: {seconds}");
result = (ushort)((seconds >> 8) & 0xFFFF);
Console.WriteLine($"--- (x >> 8) & 0xFFFF: {result}");
}
var ssss_LE = BitConverter.GetBytes(result);
// returns 2 little endian bytes array from the ushort result
Console.WriteLine($"--- SSSS (LE): {BitConverter.ToString(ssss_LE).Replace("-", " ")}");
return ssss_LE;
}
static byte[] Calculate_IIII_LE(this OmniUniProConnection connection)
{
// response with status byte at the start
byte[] response = connection.Send(0x01);
int responseLength = Math.Max(response.Length - 1, 0);
string factoryID = Encoding
.ASCII
.GetString(response, 1, responseLength)
.Trim('\0')
.Trim();
ushort crcU16 = 0;
Console.WriteLine($"--- Factory ID: {factoryID}");
if (response[0] == 0x01)
{
byte[] plainData;
if (string.IsNullOrWhiteSpace(factoryID))
{
plainData = Encoding.ASCII.GetBytes("Factory");
}
else
{
plainData = Encoding.ASCII.GetBytes(factoryID);
}
Console.WriteLine($"--- Bytes to encode: {BitConverter.ToString(plainData).Replace("-", " ")}");
foreach (byte byteU8 in plainData)
{
ushort tempU16 = crcU16;
crcU16 = (ushort)(tempU16 >> 8);
crcU16 += (ushort)(tempU16 << 8);
crcU16 ^= byteU8;
tempU16 = (ushort)((crcU16 >> 4) & 0x000F);
crcU16 ^= tempU16;
tempU16 = (ushort)((crcU16 & 0x000F) << 12);
crcU16 ^= tempU16;
tempU16 = (ushort)((crcU16 & 0x00FF) << 5);
crcU16 ^= tempU16;
}
}
byte[] crc_Bytes_LE = BitConverter.GetBytes(crcU16);
Console.WriteLine($"--- CRC uint16: {crcU16}");
Console.WriteLine($"--- IIII (LE): {BitConverter.ToString(crc_Bytes_LE).Replace("-", " ")}");
// returns 2 little endian bytes array from the ushort crcU16
return crc_Bytes_LE;
}
static byte[] Calculate_CCCC_LE(this OmniUniProConnection connection)
{
// response with status byte at the start
byte[] response = connection.Send(0x07);
int responseLength = Math.Max(response.Length - 1, 0);
string customerText = Encoding
.ASCII
.GetString(response, 1, responseLength)
.Trim('\0');
Console.WriteLine($"--- Customer text: {customerText}");
byte[] cccc = new byte[2];
if (response[0] == 0x01)
{
byte[] plainData = new byte[4];
if (string.IsNullOrWhiteSpace(customerText))
{
plainData = Encoding.ASCII.GetBytes("Factory");
}
else if (customerText.Length < 4)
{
Encoding.ASCII.GetBytes(customerText).CopyTo(plainData, 0);
}
else
{
plainData = Encoding.ASCII.GetBytes(customerText);
}
Console.WriteLine($"--- Text to encode: {Encoding.ASCII.GetString(plainData)}");
Console.Write("--- |");
byte[] bits = new byte[16];
string hex = string.Empty;
// for each byte from the first 4 bytes
for (int i = 0; i < 4; i++)
{
byte current = plainData[i];
byte count1 = 0;
Console.Write($"{current}:");
// count bits set to 1
for (int b = 0; b < 8; b++)
{
int bit = current >> b & 1;
count1 += (byte)bit;
Console.Write(bit);
}
hex += count1;
Console.Write($":{count1}|");
}
Console.WriteLine();
cccc[0] = Convert.ToByte(hex.Substring(0, 2), 16);
cccc[1] = Convert.ToByte(hex.Substring(2, 2), 16);
}
Console.WriteLine($"--- CCCC (LE): {BitConverter.ToString(cccc).Replace("-", " ")}");
return cccc;
}
static byte[] Calculate_VVVV_LE(this OmniUniProConnection connection)
{
byte[] response = connection.Send(0x13);
int responseLength = Math.Max(response.Length - 1, 0);
string readingPreset = Encoding
.ASCII
.GetString(response, 1, responseLength)
.Trim('\0');
Console.WriteLine($"--- Customer text: {readingPreset}");
Console.WriteLine($"--- Reading preset: {Encoding.ASCII.GetString(response)}");
ushort result = 0;
if (response[0] == 0x01)
{
byte[] bytes = new byte[4];
Array.Copy(response, 3, bytes, 0, 4);
bytes = bytes.Reverse().ToArray();
// copies response bytes 3..6
uint number = BitConverter.ToUInt32(bytes, 0);
Console.WriteLine($"--- UInt32: {number}");
result = (ushort)(number % 11);
Console.WriteLine($"--- UInt32 % 11: {result}");
}
byte[] vvvv_LE = BitConverter.GetBytes(result);
Console.WriteLine($"--- VVVV (LE): {BitConverter.ToString(vvvv_LE).Replace("-", " ")}");
// returns 2 little endian bytes array from the ushort result
return vvvv_LE;
}
}
}
+15 -166
View File
@@ -1,184 +1,33 @@
namespace CommonConsole
{
using OmniPlus;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
public class Program
public partial class Program
{
//[DllImport("GMH3x32E.dll")]
//public static extern Int16 UniversalOpenCom(Int16 ini16COMPortNumber, UInt32 inui32BaudRate, Int16 inui16ConverterType, Int16 ini16Parity, Int16 ini16StoppBits);
//[DllImport("GMH3x32E.dll")]
//public static extern Int16 GMH_CloseCom();
//[DllImport("GMH3x32E.dll")]
//unsafe public static extern Int16 GMH_Transmit(Int16 ini16DeviceAddress, Int16 ini16TransmitCode, Int16* refi16ptrPriority, double* refdblptrFloatValue, Int32* refi32ptrIntegerValue);
public static void Main()
{
// UniversalOpenCom(12, 4800, 8, 0, 0);
// Int16 i16Priority;
// Double dblFloatValue;
// Int32 i32IntergerValue;
// unsafe
// {
// var i16ErrorCode = GMH_Transmit(1, 0, &i16Priority, &dblFloatValue, &i32IntergerValue);
// }
// Console.WriteLine(dblFloatValue);
// GMH_CloseCom();
}
//public static void Main(string[] args)
//public static void Main()
//{
// var messurementLines = File.ReadLines(@".\messurements.txt");
// var messurements = new List<Messurement>();
// //var connection = new OmniUniProConnection("COM16");
// var connection = new OmniIrdaConnection("COM4");
// connection.StateChenged += Console.WriteLine;
// var parsedData = new List<MessurementData>();
// var us = new CultureInfo("en-US");
// var de = new CultureInfo("de-DE");
// var any = NumberStyles.Any;
// var skipNext = true;
// foreach (var line in messurementLines)
// {
// if (string.IsNullOrWhiteSpace(line))
// {
// if (parsedData.Count > 0)
// {
// messurements.Add(new Messurement
// {
// PcbId = parsedData.First().PcbId,
// Start = parsedData.Min(x => x.Timestamp),
// MinT = parsedData.Min(x => x.CurrentT),
// MinTOF = parsedData.Min(x => x.CurrentTOF),
// AvgT = parsedData.Average(x => x.CurrentT),
// AvgTOF = parsedData.Average(x => x.CurrentTOF),
// MaxT = parsedData.Max(x => x.CurrentT),
// MaxTOF = parsedData.Max(x => x.CurrentTOF),
// End = parsedData.Max(x => x.Timestamp),
// });
// }
// parsedData = new List<MessurementData>();
// skipNext = true;
// continue;
// }
// if (skipNext)
// {
// skipNext = false;
// continue;
// }
// var lineTokens = line.Split(new[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);
// if (lineTokens.Length != 4)
// {
// continue;
// }
// var dateString = lineTokens[0];
// var pcbId = lineTokens[1];
// var temperatureString = lineTokens[2];
// var tofString = lineTokens[3];
// _ = DateTime.TryParse(dateString.Substring(1, dateString.Length - 2), out var timestamp);
// _ = double.TryParse(temperatureString, any, us, out var currentT) || double.TryParse(temperatureString, any, de, out currentT);
// _ = double.TryParse(tofString, any, us, out var currentTOF) || double.TryParse(tofString, any, de, out currentT);
// parsedData.Add(new MessurementData
// {
// PcbId = pcbId,
// CurrentT = currentT,
// CurrentTOF = currentTOF,
// Timestamp = timestamp
// });
// }
// File.WriteAllLines(@".\messurements.csv", messurements.Select(x
// => $"{x.PcbId,10}\t"
// + $"{x.AvgT,5:0.00}\t"
// + $"{x.AvgTOF,12:0.0000000000}\t"
// + $"{x.DifferenceT,5:00.00}\t"
// + $"{x.DifferenceTOF,12:0.0000000000}"));
// Console.WriteLine(Messurement.Header);
// messurements.ForEach(Console.WriteLine);
// connection.Open();
// connection.FactorySeal(true);
// connection.FactorySeal();
// connection.Close();
//}
}
public class MessurementData
{
public string PcbId { get; set; }
public double CurrentT { get; set; }
public double CurrentTOF { get; set; }
public DateTime Timestamp { get; set; }
}
public class Messurement
{
public string PcbId { get; set; }
public DateTime Start { get; set; }
public double MinTOF { get; set; }
public double MinT { get; set; }
public double AvgTOF { get; set; }
public double AvgT { get; set; }
public double MaxTOF { get; set; }
public double MaxT { get; set; }
public DateTime End { get; set; }
public double DifferenceT => Math.Abs(this.MaxT - this.MinT);
public double DifferenceTOF => Math.Abs(this.MaxTOF - this.MinTOF);
public override String ToString()
=> $"{this.PcbId,10}\t"
+ $"{this.Start,21:yyyy-MM-dd hh:mm:ss}\t"
+ $"{this.MinT,5:0.00}\t"
+ $"{this.MinTOF,12:0.0000000000}\t"
+ $"{this.AvgT,5:0.00}\t"
+ $"{this.AvgTOF,12:0.0000000000}\t"
+ $"{this.MaxT,5:0.00}\t"
+ $"{this.MaxTOF,12:0.0000000000}\t"
+ $"{this.End,21:yyyy-MM-dd hh:mm:ss}\t"
+ $"{this.DifferenceT,5:00.00}\t"
+ $"{this.DifferenceTOF,12:0.0000000000}";
public static string Header
=> $"{"PcbId",10}\t"
+ $"{"Start",21}\t"
+ $"{"Min T",5}\t"
+ $"{"Min TOF",12}\t"
+ $"{"Avg T",5}\t"
+ $"{"Avg TOF",12}\t"
+ $"{"Max T",5}\t"
+ $"{"Max TOF",12}\t"
+ $"{"End",21}\t"
+ $"{"Dif T",5}\t"
+ $"{"Dif TOF",12}";
}
}
}
@@ -0,0 +1,43 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
namespace CommonConsole
{
public static class ReflectionExtensions
{
private static readonly ConcurrentDictionary<Type, IDictionary<Func<Object, Object[], Object>, Action<Object, Object, Object[]>>> metadata
= new ConcurrentDictionary<Type, IDictionary<Func<object, object[], object>, Action<object, object, object[]>>>();
public static void CopyTo<T>(this T source, T destination) where T : class
{
var type = typeof(T);
var properties = metadata.GetOrAdd(type, AddTypeProperties);
foreach (var kvp in properties)
{
var getter = kvp.Key;
var setter = kvp.Value;
var value = getter(source, null);
setter(destination, value, null);
}
}
private static IDictionary<Func<Object, Object[], Object>, Action<Object, Object, Object[]>> AddTypeProperties(Type type)
{
var properties = new Dictionary<Func<Object, Object[], Object>, Action<Object, Object, Object[]>>();
foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (property.CanWrite)
{
properties[property.GetValue] = property.SetValue;
}
}
return properties;
}
}
}
+158
View File
@@ -0,0 +1,158 @@
namespace CommonConsole
{
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
public partial class Program
{
class Outer
{
private readonly Middle middle;
Outer(Middle middle)
{
Console.WriteLine($"{nameof(Outer)}: I am transient!");
this.middle = middle;
}
internal string Text => $"{nameof(Outer)}.{nameof(Text)} => {this.middle.Text}";
}
class Middle
{
private readonly Inner inner;
Middle(Inner inner)
{
Console.WriteLine($"{nameof(Middle)}: I am transient!");
this.inner = inner;
}
internal string Text => $"{nameof(Middle)}.{nameof(Text)} => {this.inner.Text}";
}
class Inner
{
private readonly string text;
internal Inner(string text)
{
Console.WriteLine($"{nameof(Inner)}: I am singleton!");
this.text = text;
}
internal string Text => $"{nameof(Inner)}.{nameof(Text)} => {this.text}";
}
public static void DependencyInjectionTest()
{
ServiceProvider
.ServiceCollection
.AddSingleton(new Inner("It works!"));
var outer = ServiceProvider.GetService<Outer>();
Console.WriteLine(outer.Text);
}
}
public interface IServiceCollection
{
IServiceCollection AddSingleton<T>(T instance);
}
public class ServiceProvider : IServiceProvider, IServiceCollection
{
private static readonly ServiceProvider serviceProvider = new ServiceProvider();
private readonly ConcurrentDictionary<Type, object> services;
private ServiceProvider()
{
this.services = new ConcurrentDictionary<Type, object>();
}
public IServiceCollection AddSingleton<T>(T instance)
{
services.AddOrUpdate(typeof(T), instance, (t, i) => instance);
return this;
}
public object GetService(Type serviceType)
{
return services.GetOrAdd(serviceType, default(object));
}
public static IServiceCollection ServiceCollection
{
get => serviceProvider;
}
public static T GetService<T>()
{
var serviceType = typeof(T);
var serviceInstance = default(T);
if (serviceProvider.GetService(serviceType) is T existingInstance)
{
serviceInstance = existingInstance;
}
else if (CreateInstance(serviceType) is T newInstance)
{
serviceInstance = newInstance;
}
return serviceInstance;
}
private static object CreateInstance(Type instanceType)
{
var instance = default(object);
var constructors = instanceType
.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.OrderByDescending(x => x.GetParameters().Length);
foreach (var constructor in constructors)
{
var parameters = constructor.GetParameters();
var parametersLength = parameters.Length;
var createParameters = new object[parametersLength];
for (int i = 0; i < parametersLength; i++)
{
var parameterType = parameters[i].ParameterType;
var parameter = serviceProvider.GetService(parameterType);
if (parameter is null)
{
parameter = CreateInstance(parameterType);
}
createParameters[i] = parameter;
}
try
{
instance = constructor.Invoke(createParameters);
if (instance != null)
{
break;
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
return instance;
}
}
}
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
-4
View File
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net481" />
</packages>
@@ -4,12 +4,12 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C27BA66C-C3A7-48A2-A644-CBA77E28E531}</ProjectGuid>
<ProjectGuid>{1743B349-E347-4DCF-A106-15AE3F95C3A3}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SIRTBroadcaster.Abstraction</RootNamespace>
<AssemblyName>SIRTBroadcaster.Abstraction</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<RootNamespace>Common.Abstraction</RootNamespace>
<AssemblyName>Common.Abstraction</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
@@ -31,9 +31,6 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@@ -44,20 +41,10 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="IMessageSender.cs" />
<Compile Include="ISIRTBroadcaster.cs" />
<Compile Include="ISIRTBroadcasterClient.cs" />
<Compile Include="ISIRTBroadcasterHost.cs" />
<Compile Include="SIRTMessage.cs" />
<Compile Include="SIRTConnection.cs" />
<Compile Include="SIRTModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SIRTExtensions.cs" />
<Compile Include="SIRTFixed.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<Folder Include="Interfaces\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
@@ -5,11 +5,11 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SIRTBroadcaster.UI")]
[assembly: AssemblyTitle("Common.Abstraction")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SIRTBroadcaster.UI")]
[assembly: AssemblyProduct("Common.Abstraction")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2550b77d-d975-4a50-9c6a-526d4e07754d")]
[assembly: Guid("1743b349-e347-4dcf-a106-15ae3f95c3a3")]
// Version information for an assembly consists of the following four values:
//
@@ -0,0 +1,10 @@
namespace ExchangeHub.Contracts
{
public delegate void VoidEventHandler(string groupName);
public delegate void IntEventHandler(int value, string groupName);
public delegate void DoubleEventHandler(double value, string groupName);
public delegate void StringEventHandler(string value, string groupName);
}
@@ -0,0 +1,43 @@
namespace ExchangeHub.Contracts
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Only for COM usage.
/// Exposes event handlers for the (VB6) master.
/// </summary>
[Guid("9FAA6100-E33F-46F7-9151-C85903472388")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IExchangeEvents
{
/// <summary>
/// On received: VB6 should stop all running tasks.
/// </summary>
void Disposed(string groupName);
/// <summary>
/// On received: VB6 should start given flow.
/// On sent: VB6 notifies that the flow is reached.
/// </summary>
void StartFlow(double valueM3H, string groupName);
/// <summary>
/// On received: VB6 should stop any flow.
/// On sent: VB6 notifies that the flow is stopped.
/// </summary>
void StopFlow(string groupName);
/// <summary>
/// On received: VB6 should start reference volume messuring.
/// On sent: VB6 notifies that the reference messuring has started.
/// </summary>
void StartReferenceMessurement(int durationSeconds, string groupName);
/// <summary>
/// On received: VB6 should stop reference volume messuring.
/// On sent: VB6 sends the volume messured.
/// </summary>
void StopReferenceMessurement(double valueM3, string groupName);
}
}
@@ -0,0 +1,10 @@
namespace ExchangeHub.Contracts
{
/// <summary>
/// <para>Only for the SignalR host.</para>
/// <para>Exposes used events as methods.</para>
/// </summary>
public interface IExchangeHub : IExchangeEvents
{
}
}
@@ -0,0 +1,22 @@
namespace ExchangeHub.Contracts
{
using System;
using System.Runtime.InteropServices;
[Guid("21EA6C57-A004-456E-8D99-7DCAD3481205")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IExchangeHubMaster : IExchangeHubSlave
{
void Connect(string url);
void SendDisposed(string _ = "");
void SendStartFlow(double volumeM3H, string _ = "");
void SendStopFlow(string _ = "");
void SendStartReferenceMessurement(int durationSeconds, string _ = "");
void SendStopReferenceMessurement(double volumeM3 = 0D, string _ = "");
}
}
@@ -0,0 +1,15 @@
namespace ExchangeHub.Contracts
{
public interface IExchangeHubSlave
{
event VoidEventHandler Disposed;
event DoubleEventHandler StartFlow;
event VoidEventHandler StopFlow;
event IntEventHandler StartReferenceMessurement;
event DoubleEventHandler StopReferenceMessurement;
}
}
@@ -0,0 +1,236 @@
namespace ExchangeHub
{
using ExchangeHub.Contracts;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Client;
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IExchangeEvents))]
[Guid("2ABFAC6C-9F3C-4702-9E08-4979A26577EF")]
[ProgId("ExchangeHub.ExchangeConnection")]
public class ExchangeConnection : IExchangeHubMaster
{
public const string GROUP_KEY = "GroupNameKey";
public const string HUB_NAME = "ExchangeHub";
public const string STR_EMPTY = "";
private static readonly string GroupName = Environment.MachineName;
private readonly ICollection<IDisposable> disposables;
private HubConnection connection;
private IHubProxy proxy;
public ExchangeConnection()
=> this.disposables = new List<IDisposable>();
public event VoidEventHandler Disposed;
public event DoubleEventHandler StartFlow;
public event VoidEventHandler StopFlow;
public event IntEventHandler StartReferenceMessurement;
public event DoubleEventHandler StopReferenceMessurement;
public event StringEventHandler StateChanged;
public void Connect(string url)
{
this.connection = new HubConnection(url, queryString: $"{GROUP_KEY}={Environment.MachineName}");
this.connection.Closed += this.Connection_Closed;
this.connection.ConnectionSlow += this.Connection_ConnectionSlow;
this.connection.Error += this.Connection_Error;
this.connection.Received += this.Connection_Received;
this.connection.Reconnected += this.Connection_Reconnected;
this.connection.Reconnecting += this.Connection_Reconnecting;
this.connection.StateChanged += this.Connection_StateChanged;
this.proxy = this.connection.CreateHubProxy(HUB_NAME);
this.disposables.Add(this.proxy.On<string>( nameof(this.Disposed), this.ReceiveDisposed));
this.disposables.Add(this.proxy.On<double, string>( nameof(this.StartFlow), this.FlowStarted));
this.disposables.Add(this.proxy.On<string>( nameof(this.StopFlow), this.FlowStopped));
this.disposables.Add(this.proxy.On<int, string>( nameof(this.StartReferenceMessurement), this.MessurementStarted));
this.disposables.Add(this.proxy.On<double, string>( nameof(this.StopReferenceMessurement), this.MessurementStopped));
try
{
this.connection
.Start()
.Wait();
}
catch (Exception e)
{
this.NotifyStateChanged(e.ToString());
}
}
public void Disconnect()
{
try
{
this.SendDisposed();
this.connection.Closed -= this.Connection_Closed;
this.connection.ConnectionSlow -= this.Connection_ConnectionSlow;
this.connection.Error -= this.Connection_Error;
this.connection.Received -= this.Connection_Received;
this.connection.Reconnected -= this.Connection_Reconnected;
this.connection.Reconnecting -= this.Connection_Reconnecting;
this.connection.StateChanged -= this.Connection_StateChanged;
foreach (var disposable in this.disposables)
{
disposable.Dispose();
}
Task.Factory.StartNew(this.connection.Dispose);
this.NotifyStateChanged($"Connection disconnected.");
}
catch (Exception e)
{
this.NotifyStateChanged(e.ToString());
}
}
public void SendDisposed(string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke<string>(nameof(this.Disposed), GroupName);
this.NotifyStateChanged($"{nameof(SendDisposed)}");
}
}
public void SendStartFlow(double volumeM3H, string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke(nameof(this.StartFlow), volumeM3H, GroupName);
this.NotifyStateChanged($"{nameof(SendStartFlow)}");
}
}
public void SendStopFlow(string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke(nameof(this.StopFlow), GroupName);
this.NotifyStateChanged($"{nameof(SendStopFlow)}");
}
}
public void SendStartReferenceMessurement(int durationSeconds, string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke(nameof(this.StartReferenceMessurement), durationSeconds, GroupName);
this.NotifyStateChanged($"{nameof(SendStartReferenceMessurement)}");
}
}
public void SendStopReferenceMessurement(double volumeM3H = 0D, string _ = STR_EMPTY)
{
if (this.connection?.State == ConnectionState.Connected)
{
this.proxy.Invoke(nameof(this.StopReferenceMessurement), volumeM3H, GroupName);
this.NotifyStateChanged($"{nameof(SendStopReferenceMessurement)}");
}
}
private void ReceiveDisposed(string groupName)
{
if (GroupName == groupName)
{
this.Disposed?.Invoke(groupName);
this.NotifyStateChanged($"{nameof(Disposed)}");
}
}
private void FlowStarted(double volumeM3H, string groupName)
{
if (GroupName == groupName)
{
this.StartFlow?.Invoke(volumeM3H, groupName);
this.NotifyStateChanged($"{nameof(FlowStarted)} -> {volumeM3H}m³/h");
}
}
private void FlowStopped(string groupName)
{
if (GroupName == groupName)
{
this.StopFlow?.Invoke(groupName);
this.NotifyStateChanged($"{nameof(FlowStopped)}");
}
}
private void MessurementStarted(int seconds, string groupName)
{
if (GroupName == groupName)
{
this.StartReferenceMessurement?.Invoke(seconds, groupName);
this.NotifyStateChanged($"{nameof(MessurementStarted)} -> {seconds}s");
}
}
private void MessurementStopped(double volumeMessured, string groupName)
{
if (GroupName == groupName)
{
this.StopReferenceMessurement?.Invoke(volumeMessured, groupName);
this.NotifyStateChanged($"{nameof(MessurementStopped)} -> {volumeMessured}m³/h");
}
}
private void Connection_Closed()
{
this.NotifyStateChanged("HubConnection closed!");
}
private void Connection_ConnectionSlow()
{
this.NotifyStateChanged("HubConnection is about to timeout!");
}
private void Connection_Error(Exception e)
{
this.NotifyStateChanged(e.ToString());
}
private void Connection_Received(string data)
{
this.NotifyStateChanged(data);
}
private void Connection_Reconnected()
{
this.NotifyStateChanged("HubConnection reconnected!");
}
private void Connection_Reconnecting()
{
this.NotifyStateChanged("HubConnection reconnecting!");
}
private void Connection_StateChanged(StateChange state)
{
this.NotifyStateChanged($"{state.OldState} -> {state.NewState}");
}
private void NotifyStateChanged(string text)
{
try
{
this.StateChanged?.Invoke(text, GroupName);
}
catch (Exception e)
{
this.StateChanged?.Invoke(e.ToString(), GroupName);
}
}
}
}
@@ -4,12 +4,12 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}</ProjectGuid>
<ProjectGuid>{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SIRTBroadcaster.Host</RootNamespace>
<AssemblyName>SIRTBroadcaster.Host</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<RootNamespace>ExchangeHub</RootNamespace>
<AssemblyName>ExchangeHub</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
@@ -32,32 +32,27 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNet.SignalR.Client, Version=2.4.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.SignalR.Client.2.4.3\lib\net45\Microsoft.AspNet.SignalR.Client.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.SignalR.Client.2.4.3\lib\net40\Microsoft.AspNet.SignalR.Client.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.6.0.4\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ISIRTListener.cs" />
<Compile Include="Contracts\EventHandlers.cs" />
<Compile Include="Contracts\IExchangeEvents.cs" />
<Compile Include="Contracts\IExchangeHub.cs" />
<Compile Include="Contracts\IExchangeHubMaster.cs" />
<Compile Include="Contracts\IExchangeHubSlave.cs" />
<Compile Include="ExchangeConnection.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SIRTBroadcasterHost.cs" />
<Compile Include="SIRTListener.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SIRTBroadcaster.Abstraction\SIRTBroadcaster.Abstraction.csproj">
<Project>{C27BA66C-C3A7-48A2-A644-CBA77E28E531}</Project>
<Name>SIRTBroadcaster.Abstraction</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
@@ -5,11 +5,11 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("LaaProduction.Personalization.Updater")]
[assembly: AssemblyTitle("ExchangeHub")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LaaProduction.Personalization.Updater")]
[assembly: AssemblyProduct("ExchangeHub")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -17,10 +17,10 @@ using System.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
[assembly: ComVisible(true)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4b7f1659-2a57-414c-a192-fa0a822b6612")]
[assembly: Guid("6033ff0c-cf32-4bc5-8efe-4774ccdc663d")]
// Version information for an assembly consists of the following four values:
//
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.SignalR.Client" version="2.4.3" targetFramework="net481" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net481" />
<package id="Microsoft.AspNet.SignalR.Client" version="2.4.3" targetFramework="net40" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net40" />
</packages>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<appSettings>
<add key="PSNR" value="1000"/>
<add key="HubURL" value="http://sla12iis01.emea.sensus.net/LaaProductionWeb" />
<!--<add key="OmniDB" value="Server=SLASQL01.emea.sensus.net; Database=AuftragKopie; User ID=sa; Password=sqlserver;" />-->
<add key="OmniDB" value="Server=SLASQL01.emea.sensus.net; Database=Auftrag; User ID=sa; Password=sqlserver;"/>
<!--<add key="COMPorts" value="COM1, COM3, COM5, COM7, COM5, COM9, COM11, COM13, COM15, COM17"/>-->
<add key="COMPorts" value="COM4"/>
</appSettings>
</configuration>
+305
View File
@@ -0,0 +1,305 @@
<Application x:Class="InspectionUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style x:Key="Spinner" TargetType="{x:Type Path}">
<Setter Property="Data" Value="M 10 3 C 6.13401 3 3 6.13401 3 10 C 3 10.2761 2.77614 10.5 2.5 10.5 C 2.22386 10.5 2 10.2761 2 10 C 2 5.58172 5.58172 2 10 2 C 14.4183 2 18 5.58172 18 10 C 18 14.4183 14.4183 18 10 18 C 9.72386 18 9.5 17.7761 9.5 17.5 C 9.5 17.2239 9.72386 17 10 17 C 13.866 17 17 13.866 17 10 C 17 6.13401 13.866 3 10 3 Z" />
<Setter Property="Stretch" Value="Uniform" />
<Setter Property="Fill" Value="LightGray" />
<Setter Property="Stroke" Value="Transparent" />
<Setter Property="StrokeEndLineCap" Value="Flat" />
<Setter Property="StrokeStartLineCap" Value="Flat" />
<Setter Property="StrokeThickness" Value="0.5" />
<Setter Property="RenderTransformOrigin" Value="0.5, 0.5" />
<Setter Property="RenderTransform">
<Setter.Value>
<RotateTransform />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"
From="0"
To="360"
Duration="0:0:1"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="ComboboxFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" StrokeDashArray="1 2" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" SnapsToDevicePixels="true" StrokeThickness="1"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="TextBox.Static.Background" Color="#FFFFFFFF"/>
<Style x:Key="ComboBoxEditableTextBox" TargetType="{x:Type TextBox}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="MinWidth" Value="0"/>
<Setter Property="MinHeight" Value="0"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer x:Name="PART_ContentHost" Background="Transparent" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="ComboBox.Static.Background" Color="White" />
<SolidColorBrush x:Key="ComboBox.Static.Border" Color="White"/>
<SolidColorBrush x:Key="ComboBox.Static.Glyph" Color="#FF606060"/>
<SolidColorBrush x:Key="ComboBox.Static.Editable.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ComboBox.Static.Editable.Border" Color="White"/>
<SolidColorBrush x:Key="ComboBox.Static.Editable.Button.Background" Color="Transparent"/>
<SolidColorBrush x:Key="ComboBox.Static.Editable.Button.Border" Color="Transparent"/>
<LinearGradientBrush x:Key="ComboBox.MouseOver.Background" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFECF4FC" Offset="0.0"/>
<GradientStop Color="#FFDCECFC" Offset="1.0"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ComboBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="ComboBox.MouseOver.Glyph" Color="#FF000000"/>
<SolidColorBrush x:Key="ComboBox.MouseOver.Editable.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ComboBox.MouseOver.Editable.Border" Color="#FF7EB4EA"/>
<LinearGradientBrush x:Key="ComboBox.MouseOver.Editable.Button.Background" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFEBF4FC" Offset="0.0"/>
<GradientStop Color="#FFDCECFC" Offset="1.0"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ComboBox.MouseOver.Editable.Button.Border" Color="#FF7EB4EA"/>
<LinearGradientBrush x:Key="ComboBox.Pressed.Background" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFDAECFC" Offset="0.0"/>
<GradientStop Color="#FFC4E0FC" Offset="1.0"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ComboBox.Pressed.Border" Color="#FF569DE5"/>
<SolidColorBrush x:Key="ComboBox.Pressed.Glyph" Color="#FF000000"/>
<SolidColorBrush x:Key="ComboBox.Pressed.Editable.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ComboBox.Pressed.Editable.Border" Color="#FF569DE5"/>
<LinearGradientBrush x:Key="ComboBox.Pressed.Editable.Button.Background" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFDAEBFC" Offset="0.0"/>
<GradientStop Color="#FFC4E0FC" Offset="1.0"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ComboBox.Pressed.Editable.Button.Border" Color="#FF569DE5"/>
<SolidColorBrush x:Key="ComboBox.Disabled.Background" Color="#FFF0F0F0"/>
<SolidColorBrush x:Key="ComboBox.Disabled.Border" Color="#FFD9D9D9"/>
<SolidColorBrush x:Key="ComboBox.Disabled.Glyph" Color="#FFBFBFBF"/>
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Border" Color="#FFBFBFBF"/>
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Button.Background" Color="Transparent"/>
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Button.Border" Color="Transparent"/>
<Style x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="ClickMode" Value="Press"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="templateRoot" Background="{StaticResource ComboBox.Static.Background}" BorderBrush="{StaticResource ComboBox.Static.Border}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
<Border x:Name="splitBorder" BorderBrush="Transparent" BorderThickness="1" HorizontalAlignment="Right" Margin="0" SnapsToDevicePixels="true" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
<Path x:Name="arrow" Data="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" Fill="{StaticResource ComboBox.Static.Glyph}" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center" Width="8" Stretch="Uniform"/>
</Border>
</Border>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}}" Value="true"/>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Mode=Self}}" Value="false"/>
<Condition Binding="{Binding IsPressed, RelativeSource={RelativeSource Mode=Self}}" Value="false"/>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Mode=Self}}" Value="true"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="{StaticResource ComboBox.Static.Editable.Background}"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource ComboBox.Static.Editable.Border}"/>
<Setter Property="Background" TargetName="splitBorder" Value="{StaticResource ComboBox.Static.Editable.Button.Background}"/>
<Setter Property="BorderBrush" TargetName="splitBorder" Value="{StaticResource ComboBox.Static.Editable.Button.Border}"/>
</MultiDataTrigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="arrow" Value="{StaticResource ComboBox.MouseOver.Glyph}"/>
</Trigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Mode=Self}}" Value="true"/>
<Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}}" Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="{StaticResource ComboBox.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource ComboBox.MouseOver.Border}"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Mode=Self}}" Value="true"/>
<Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}}" Value="true"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="{StaticResource ComboBox.MouseOver.Editable.Background}"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource ComboBox.MouseOver.Editable.Border}"/>
<Setter Property="Background" TargetName="splitBorder" Value="{StaticResource ComboBox.MouseOver.Editable.Button.Background}"/>
<Setter Property="BorderBrush" TargetName="splitBorder" Value="{StaticResource ComboBox.MouseOver.Editable.Button.Border}"/>
</MultiDataTrigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Fill" TargetName="arrow" Value="{StaticResource ComboBox.Pressed.Glyph}"/>
</Trigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsPressed, RelativeSource={RelativeSource Mode=Self}}" Value="true"/>
<Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}}" Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="{StaticResource ComboBox.Pressed.Background}"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource ComboBox.Pressed.Border}"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsPressed, RelativeSource={RelativeSource Mode=Self}}" Value="true"/>
<Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}}" Value="true"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="{StaticResource ComboBox.Pressed.Editable.Background}"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource ComboBox.Pressed.Editable.Border}"/>
<Setter Property="Background" TargetName="splitBorder" Value="{StaticResource ComboBox.Pressed.Editable.Button.Background}"/>
<Setter Property="BorderBrush" TargetName="splitBorder" Value="{StaticResource ComboBox.Pressed.Editable.Button.Border}"/>
</MultiDataTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="arrow" Value="{StaticResource ComboBox.Disabled.Glyph}"/>
</Trigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Mode=Self}}" Value="false"/>
<Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}}" Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="{StaticResource ComboBox.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource ComboBox.Disabled.Border}"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Mode=Self}}" Value="false"/>
<Condition Binding="{Binding IsEditable, RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}}" Value="true"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="{StaticResource ComboBox.Disabled.Editable.Background}"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="{StaticResource ComboBox.Disabled.Editable.Border}"/>
<Setter Property="Background" TargetName="splitBorder" Value="{StaticResource ComboBox.Disabled.Editable.Button.Background}"/>
<Setter Property="BorderBrush" TargetName="splitBorder" Value="{StaticResource ComboBox.Disabled.Editable.Button.Border}"/>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="ComboBoxEditableTemplate" TargetType="{x:Type ComboBox}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
</Grid.ColumnDefinitions>
<Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource Mode=TemplatedParent}}" Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}">
<Border x:Name="dropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1">
<ScrollViewer x:Name="DropDownScrollViewer">
<Grid x:Name="grid" RenderOptions.ClearTypeHint="Enabled">
<Canvas x:Name="canvas" HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="opaqueRect" Fill="{Binding Background, ElementName=dropDownBorder}" Height="{Binding ActualHeight, ElementName=dropDownBorder}" Width="{Binding ActualWidth, ElementName=dropDownBorder}"/>
</Canvas>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ScrollViewer>
</Border>
</Popup>
<ToggleButton x:Name="toggleButton" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" Style="{StaticResource ComboBoxToggleButton}"/>
<Border x:Name="border" Background="{StaticResource TextBox.Static.Background}" Margin="{TemplateBinding BorderThickness}">
<TextBox x:Name="PART_EditableTextBox" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource Mode=TemplatedParent}}" Margin="{TemplateBinding Padding}" Style="{StaticResource ComboBoxEditableTextBox}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="true">
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Height" TargetName="dropDownBorder" Value="95"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
<Trigger Property="ScrollViewer.CanContentScroll" SourceName="DropDownScrollViewer" Value="false">
<Setter Property="Canvas.Top" TargetName="opaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
<Setter Property="Canvas.Left" TargetName="opaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ComboBoxTemplate" TargetType="{x:Type ComboBox}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
</Grid.ColumnDefinitions>
<Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" Margin="1" Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}">
<Border x:Name="dropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1">
<ScrollViewer x:Name="DropDownScrollViewer">
<Grid x:Name="grid" RenderOptions.ClearTypeHint="Enabled">
<Canvas x:Name="canvas" HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="opaqueRect" Fill="{Binding Background, ElementName=dropDownBorder}" Height="{Binding ActualHeight, ElementName=dropDownBorder}" Width="{Binding ActualWidth, ElementName=dropDownBorder}"/>
</Canvas>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ScrollViewer>
</Border>
</Popup>
<ToggleButton x:Name="toggleButton" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" Style="{StaticResource ComboBoxToggleButton}"/>
<ContentPresenter x:Name="contentPresenter" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" Content="{TemplateBinding SelectionBoxItem}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter Property="Height" TargetName="dropDownBorder" Value="95"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
<Trigger Property="ScrollViewer.CanContentScroll" SourceName="DropDownScrollViewer" Value="false">
<Setter Property="Canvas.Top" TargetName="opaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
<Setter Property="Canvas.Left" TargetName="opaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="ComboBoxStyle" TargetType="{x:Type ComboBox}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ComboboxFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ComboBox.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource ComboBox.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Padding" Value="6,3,5,3"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template" Value="{StaticResource ComboBoxTemplate}"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="FontFamily" Value="Consolas"/>
<Style.Triggers>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Template" Value="{StaticResource ComboBoxEditableTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
</Application.Resources>
</Application>
+26
View File
@@ -0,0 +1,26 @@
namespace InspectionUI
{
using InspectionUI.Models;
using OmniPlus;
using System;
using System.Windows;
public partial class App : Application
{
public App()
{
ServiceProvider
.ServiceCollection
.AddSingleton(new OmniContext(Appsettings.OmniDB, Appsettings.OutputDirectory));
}
internal static event Action Exiting;
protected override void OnExit(ExitEventArgs e)
{
Exiting?.Invoke();
}
}
}
@@ -4,14 +4,17 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2550B77D-D975-4A50-9C6A-526D4E07754D}</ProjectGuid>
<ProjectGuid>{01A28A70-D5E6-4898-8C22-E64400A3B80F}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>SIRTBroadcaster.UI</RootNamespace>
<AssemblyName>SIRTBroadcaster.UI</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<RootNamespace>InspectionUI</RootNamespace>
<AssemblyName>InspectionUI</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -33,78 +36,103 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="XylemCommonUiLegacyGenCtl">
<HintPath>..\Ui\LegacyGenesisControl\obj\Debug\XylemCommonUiLegacyGenCtl.dll</HintPath>
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PruefungInitialisierung.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="PruefungInitialisierung.Designer.cs">
<DependentUpon>PruefungInitialisierung.cs</DependentUpon>
</Compile>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</EmbeddedResource>
</ApplicationDefinition>
<Compile Include="ItemsGrid.xaml.cs">
<DependentUpon>ItemsGrid.xaml</DependentUpon>
</Compile>
<Compile Include="Models\AppLogger.cs" />
<Compile Include="Models\ServiceProvider.cs" />
<Compile Include="Models\Appsettings.cs" />
<Compile Include="Models\CompilerServices.cs" />
<Compile Include="ViewModels\DefaultsHeaderRow.cs" />
<Compile Include="ViewModels\DefaultsRowVM.cs" />
<Compile Include="ViewModels\HeadersRowVM.cs" />
<Compile Include="ViewModels\ItemsGridActionsVM.cs" />
<Compile Include="ViewModels\ItemsGridHeaderVM.cs" />
<Compile Include="ViewModels\ItemsGridRowVM.cs" />
<Compile Include="ViewModels\ItemsGridVM.cs" />
<Compile Include="ViewModels\MainVM.cs" />
<Compile Include="ViewModels\MetersPoolVM.cs" />
<Compile Include="ViewModels\MeterVM.cs" />
<Compile Include="ViewModels\ItemsGridCellVM.cs" />
<Compile Include="ViewModels\ReferenceMeterVM.cs" />
<Compile Include="ViewModels\VM.cs" />
<Page Include="ItemsGrid.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SIRTBroadcaster.Abstraction\SIRTBroadcaster.Abstraction.csproj">
<Project>{c27ba66c-c3a7-48a2-a644-cba77e28e531}</Project>
<Name>SIRTBroadcaster.Abstraction</Name>
<Content Include="MainWindow.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ExchangeHub\ExchangeHub.csproj">
<Project>{6033FF0C-CF32-4BC5-8EFE-4774CCDC663D}</Project>
<Name>ExchangeHub</Name>
</ProjectReference>
<ProjectReference Include="..\SIRTBroadcaster.Client\SIRTBroadcaster.Client.csproj">
<Project>{4221F992-599E-498C-A409-6D1E70E0A6F9}</Project>
<Name>SIRTBroadcaster.Client</Name>
</ProjectReference>
<ProjectReference Include="..\SIRTBroadcaster.Host\SIRTBroadcaster.Host.csproj">
<Project>{a9d1a99d-6e55-4394-86ad-b5c53e9225eb}</Project>
<Name>SIRTBroadcaster.Host</Name>
<ProjectReference Include="..\OmniPlus\OmniPlus.csproj">
<Project>{F8D84B9A-0FCF-4083-B067-8C39B7314152}</Project>
<Name>OmniPlus</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
@@ -0,0 +1,80 @@
<Grid x:Class="InspectionUI.ItemsGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:InspectionUI.ViewModels">
<Grid.Resources>
<DataTemplate DataType="{x:Type VM:ItemsGridHeaderVM}">
<Label Background="WhiteSmoke"
BorderBrush="White"
BorderThickness="0, 1, 1, 0"
Content="{Binding Value}"
FontFamily="Consolas"
FontSize="14"
FontWeight="Bold"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="{Binding HorisontalContentAlignment}"
Margin="0"
Padding="3, 5"
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"/>
</DataTemplate>
<DataTemplate DataType="{x:Type VM:ItemsGridCellVM}">
<Label Background="{Binding Background, TargetNullValue={x:Static SystemColors.WindowBrush}}"
BorderBrush="WhiteSmoke"
BorderThickness="0, 1, 1, 0"
Content="{Binding Value}"
FontFamily="Consolas"
FontSize="14"
Foreground="{Binding Foreground, TargetNullValue={x:Static SystemColors.ControlTextBrush}}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="{Binding HorisontalContentAlignment}"
Margin="0"
Padding="3, 5"
VerticalAlignment="Stretch"
VerticalContentAlignment="Center" />
</DataTemplate>
<DataTemplate DataType="{x:Type VM:ItemsGridActionsVM}">
<Border BorderBrush="WhiteSmoke"
BorderThickness="0, 1, 1, 0" >
<StackPanel HorizontalAlignment="Center"
Orientation="Horizontal"
Margin="0"
VerticalAlignment="Stretch">
<Button Background="Transparent"
BorderBrush="Transparent"
Content="A"
Cursor="Hand"
FontFamily="Consolas"
FontSize="14"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Padding="5, 0"
VerticalAlignment="Center"
VerticalContentAlignment="Center"/>
<Button Background="Transparent"
BorderBrush="Transparent"
Content="B"
Cursor="Hand"
FontFamily="Consolas"
FontSize="14"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Padding="5, 0"
VerticalAlignment="Center"
VerticalContentAlignment="Center" />
<Button Background="Transparent"
BorderBrush="Transparent"
Content="C"
Cursor="Hand"
FontFamily="Consolas"
FontSize="14"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Padding="5, 0"
VerticalAlignment="Center"
VerticalContentAlignment="Center" />
</StackPanel>
</Border>
</DataTemplate>
</Grid.Resources>
</Grid>
@@ -0,0 +1,91 @@
namespace InspectionUI
{
using InspectionUI.ViewModels;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
public partial class ItemsGrid : Grid
{
public ItemsGrid()
{
this.InitializeComponent();
}
public ItemsGridVM ItemsSource
{
get => this.GetValue(ItemsSourceProperty) as ItemsGridVM;
set => this.SetValue(ItemsSourceProperty, value);
}
}
public partial class ItemsGrid
{
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
name: nameof(ItemsSource)
, propertyType: typeof(ItemsGridVM)
, ownerType: typeof(ItemsGrid)
, typeMetadata: new FrameworkPropertyMetadata(null, ItemsSourceChanged));
private static void ItemsSourceChanged(DependencyObject control, DependencyPropertyChangedEventArgs args)
{
if (control is ItemsGrid itemsGrid)
{
if (args.OldValue is ItemsGridVM oldSource)
{
oldSource.PropertyChanged -= itemsGrid.ReorderItems;
}
if (args.NewValue is ItemsGridVM newSource)
{
newSource.PropertyChanged += itemsGrid.ReorderItems;
}
}
}
private void ReorderItems(object sender, PropertyChangedEventArgs e)
{
this.Children.Clear();
this.RowDefinitions.Clear();
this.ColumnDefinitions.Clear();
var row = 0;
var col = 0;
foreach (var rowItem in this.ItemsSource)
{
this.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
foreach (var cell in rowItem)
{
if (row == 0)
{
if (cell is ItemsGridHeaderVM header)
{
for (int i = 0; i < header.ColSpan; i++)
{
this.ColumnDefinitions.Add(new ColumnDefinition { Width = header.Width });
}
}
}
var cellContent = new ContentControl { Content = cell };
Grid.SetRow(cellContent, row);
Grid.SetRowSpan(cellContent, cell.RowSpan);
Grid.SetColumn(cellContent, col);
Grid.SetColumnSpan(cellContent, cell.ColSpan);
this.Children.Add(cellContent);
col += cell.ColSpan;
}
col = 0;
row++;
}
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

@@ -0,0 +1,118 @@
<Window x:Class="InspectionUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:InspectionUI.ViewModels"
xmlns:Local="clr-namespace:InspectionUI"
Icon="MainWindow.png"
Height="600"
Width="977">
<Window.DataContext>
<VM:MainVM />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border BorderBrush="LightGray" BorderThickness="0, 1" Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Command="{Binding Reload}"
Content="Neu laden"
Cursor="Hand"
FontFamily="Consolas"
Grid.Column="0"
IsEnabled="{Binding IsReloadEnabled}"
Margin="5, 5, 0, 5"
Padding="10, 5"/>
<TextBox Grid.Column="1"
FontFamily="Consolas"
FontWeight="Bold"
HorizontalContentAlignment="Left"
Margin="5, 5, 0, 5"
Text="{Binding SuchNr}"
Width="150"
VerticalContentAlignment="Center"/>
<ComboBox Background="White"
BorderBrush="White"
FontFamily="Consolas"
FontWeight="Bold"
Grid.Column="2"
Margin="5, 5, 0, 5"
Padding="5"
SelectedIndex="{Binding Size}"
Style="{DynamicResource ComboBoxStyle}" >
<ComboBoxItem Content="1½&quot;" Padding="10, 5" IsSelected="True" />
<ComboBoxItem Content="2&quot;" Padding="10, 5" />
</ComboBox>
<ComboBox Background="White"
BorderBrush="White"
FontFamily="Consolas"
FontWeight="Bold"
Grid.Column="3"
Margin="5, 5, 0, 5"
Padding="5"
SelectedValue="{Binding Type}"
SelectedValuePath="Content"
Style="{DynamicResource ComboBoxStyle}" >
<ComboBoxItem Content="C2" Padding="10, 5" IsSelected="True" />
<ComboBoxItem Content="R2" Padding="10, 5" />
<ComboBoxItem Content="T2" Padding="10, 5" />
</ComboBox>
<CheckBox Content="Korakturfaktor beibehalten?"
FontFamily="Consolas"
Grid.Column="4"
IsChecked="{Binding KeepCorrection}"
Margin="5, 5, 0, 5"
Padding="5, 0"
VerticalAlignment="Center"/>
<Button Command="{Binding StartInspection}"
Content="Prüfung starten"
Cursor="Hand"
FontFamily="Consolas"
Grid.Column="7"
IsEnabled="{Binding IsStartInspectionEnabled}"
Margin="5"
Padding="10, 5"/>
<Button Command="{Binding CancelInspection}"
Content="Abbrechen"
Cursor="Hand"
FontFamily="Consolas"
Grid.Column="8"
IsEnabled="{Binding IsCancelInspectionEnabled}"
Margin="5"
Padding="10, 5" />
</Grid>
</Border>
<Border Grid.Row="1" Margin="10">
<TextBlock FontFamily="Consolas"
Padding="0"
Text="{Binding Errors}"
TextWrapping="Wrap"/>
</Border>
<!-- TODO: Order head -->
<ScrollViewer Grid.Row="2"
CanContentScroll="True"
IsDeferredScrollingEnabled="True"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Hidden">
<Local:ItemsGrid ItemsSource="{Binding MetersPool}" Margin="10, 0, 10, 10" />
</ScrollViewer>
</Grid>
</Window>
@@ -0,0 +1,12 @@
namespace InspectionUI
{
using System.Windows;
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
}
}
@@ -0,0 +1,37 @@
namespace InspectionUI.Models
{
using System;
using System.Collections.Concurrent;
using System.IO;
using static System.Environment;
public class AppLogger
{
private static readonly string app_state = Path.Combine(Appsettings.OutputDirectory, $"{nameof(app_state)}.txt");
private static readonly ConcurrentQueue<object> statesQueue = new ConcurrentQueue<object>();
private static bool dequeuing;
public static void Log(object state)
{
statesQueue.Enqueue(state);
DequeueStates();
}
private static void DequeueStates()
{
if (!dequeuing)
{
dequeuing = true;
while (statesQueue.TryDequeue(out var state))
{
File.AppendAllText(app_state, $"[{DateTime.Now}] {state}{NewLine}");
}
dequeuing = false;
}
}
}
}
@@ -0,0 +1,57 @@
namespace InspectionUI.Models
{
using System;
using System.Configuration;
using System.IO;
public class Appsettings
{
private static readonly string exeLocation
= typeof(App).Assembly.Location;
private static readonly Configuration configuration
= ConfigurationManager.OpenExeConfiguration(exeLocation);
private static readonly KeyValueConfigurationCollection appsettings
= configuration.AppSettings.Settings;
public static string COMPorts
{
get => GetSetting(nameof(COMPorts));
}
public static string OmniDB
{
get => GetSetting(nameof(OmniDB));
}
public static string HubURL
{
get => GetSetting(nameof(HubURL));
}
public static string OutputDirectory
{
get
{
var currentDirectory = new FileInfo(exeLocation).DirectoryName;
var outputDirectoryToday = Path.Combine(currentDirectory, "Debug", $"{DateTime.Now:yyyy-MM-dd}");
return Directory.CreateDirectory(outputDirectoryToday).FullName;
}
}
public static string PSNR
{
get => GetSetting(nameof(PSNR));
}
private static string GetSetting(string setting)
{
var appsettingsSection = configuration.AppSettings.SectionInformation.Name;
ConfigurationManager.RefreshSection(appsettingsSection);
return appsettings[setting].Value;
}
}
}
@@ -0,0 +1,17 @@
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class CallerMemberNameAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class CallerFilePathAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class CallerLineNumberAttribute : Attribute
{
}
}
@@ -0,0 +1,101 @@
namespace InspectionUI.Models
{
using System;
using System.Collections.Concurrent;
using System.Linq;
public interface IServiceCollection
{
IServiceCollection AddSingleton<T>(T instance);
}
public class ServiceProvider : IServiceProvider, IServiceCollection
{
private static readonly ServiceProvider serviceProvider = new ServiceProvider();
private readonly ConcurrentDictionary<Type, object> services;
private ServiceProvider()
{
this.services = new ConcurrentDictionary<Type, object>();
}
public IServiceCollection AddSingleton<T>(T instance)
{
services.AddOrUpdate(typeof(T), instance, (t, i) => instance);
return this;
}
public object GetService(Type serviceType)
{
return services.GetOrAdd(serviceType, default(object));
}
public static IServiceCollection ServiceCollection
{
get => serviceProvider;
}
public static T GetService<T>()
{
var serviceType = typeof(T);
var serviceInstance = default(T);
if (serviceProvider.GetService(serviceType) is T existingInstance)
{
serviceInstance = existingInstance;
}
else if (CreateInstance(serviceType) is T newInstance)
{
serviceInstance = newInstance;
}
return serviceInstance;
}
private static object CreateInstance(Type instanceType)
{
var instance = default(object);
var constructors = instanceType
.GetConstructors()
.OrderByDescending(x => x.GetParameters().Length);
foreach (var constructor in constructors)
{
var parameters = constructor.GetParameters();
var parametersLength = parameters.Length;
var createParameters = new object[parametersLength];
for (int i = 0; i < parametersLength; i++)
{
var parameterType = parameters[i].ParameterType;
var parameter = serviceProvider.GetService(parameterType);
if (parameter is null)
{
parameter = CreateInstance(parameterType);
}
createParameters[i] = parameter;
}
try
{
instance = constructor.Invoke(createParameters);
if (instance != null)
{
break;
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
return instance;
}
}
}
@@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("InspectionUI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("InspectionUI")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -8,10 +8,10 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace SIRTBroadcaster.UI.Properties
{
namespace InspectionUI.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
@@ -19,51 +19,43 @@ namespace SIRTBroadcaster.UI.Properties
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SIRTBroadcaster.UI.Properties.Resources", typeof(Resources).Assembly);
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("InspectionUI.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set
{
set {
resourceCulture = value;
}
}
@@ -8,21 +8,17 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace SIRTBroadcaster.UI.Properties
{
namespace InspectionUI.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
public static Settings Default {
get {
return defaultInstance;
}
}
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
@@ -0,0 +1,32 @@
namespace InspectionUI.ViewModels
{
using InspectionUI.Models;
using OmniPlus;
public class DefaultsHeaderRow : ItemsGridRowVM
{
public DefaultsHeaderRow()
{
this.Add(new ItemsGridHeaderVM());
this.Add(new ItemsGridHeaderVM());
this.Add(new ItemsGridHeaderVM());
this.Add(new ItemsGridHeaderVM());
var pruefpunkte = ServiceProvider
.GetService<OmniContext>()
.Auftrag
.Pruefpunkte
.Count;
for (int i = 0; i < pruefpunkte; i++)
{
this.Add(new ItemsGridHeaderVM { Value = $"r/s" });
this.Add(new ItemsGridHeaderVM { Value = $"m³/h" });
this.Add(new ItemsGridHeaderVM { Value = $"acc. %" });
}
this.Add(new ItemsGridHeaderVM());
}
}
}
@@ -0,0 +1,31 @@
namespace InspectionUI.ViewModels
{
using InspectionUI.Models;
using OmniPlus;
public class DefaultsRowVM : ItemsGridRowVM
{
public DefaultsRowVM()
{
this.Add(new ItemsGridHeaderVM());
this.Add(new ItemsGridHeaderVM { Value = "PP:" });
this.Add(new ItemsGridHeaderVM());
this.Add(new ItemsGridHeaderVM { Value = "0.0" });
var pruefpunkte = ServiceProvider
.GetService<OmniContext>()
.Auftrag
.Pruefpunkte;
foreach (var pp in pruefpunkte)
{
this.Add(new ItemsGridHeaderVM { Value = $"{pp.Rotations}/{pp.Duration:0.0}" });
this.Add(new ItemsGridHeaderVM { Value = $"{pp.FlowM3H:0.000}" });
this.Add(new ItemsGridHeaderVM { Value = $"{pp.MinAccuracy}-{pp.MaxAccuracy}" });
}
this.Add(new ItemsGridHeaderVM { Value = "0.0" });
}
}
}
@@ -0,0 +1,35 @@
namespace InspectionUI.ViewModels
{
using InspectionUI.Models;
using OmniPlus;
public class HeadersRowVM : ItemsGridRowVM
{
public HeadersRowVM() : base()
{
this.Add(new ItemsGridHeaderVM { Width = ItemsGridHeaderVM.Auto });
this.Add(new ItemsGridHeaderVM { Value = "MeterNr", Width = ItemsGridHeaderVM.Star });
this.Add(new ItemsGridHeaderVM { Value = "SerialNr", Width = ItemsGridHeaderVM.Star });
this.Add(new ItemsGridHeaderVM { Value = "Crr.F. %", Width = ItemsGridHeaderVM.Auto });
var pruefpunkte = ServiceProvider
.GetService<OmniContext>()
.Auftrag
.Pruefpunkte;
foreach (var pp in pruefpunkte)
{
this.Add(new ItemsGridHeaderVM
{
Value = $"Q{pp.PPNR}",
Width = ItemsGridHeaderVM.Star,
ColSpan = 3
});
}
this.Add(new ItemsGridHeaderVM { Value = "Crr.F. %", Width = ItemsGridHeaderVM.Star });
}
}
}
@@ -0,0 +1,12 @@
namespace InspectionUI.ViewModels
{
internal class ItemsGridActionsVM : ItemsGridCellVM
{
private MeterVM meterVM;
public ItemsGridActionsVM(MeterVM meterVM) : base()
{
this.meterVM = meterVM;
}
}
}
@@ -0,0 +1,44 @@
namespace InspectionUI.ViewModels
{
using System.Windows;
using System.Windows.Media;
public class ItemsGridCellVM : VM
{
public ItemsGridCellVM() : base()
{
}
private string value;
public string Value
{
get => this.value;
set => this.Set(() => this.value = value);
}
private Brush background;
public Brush Background
{
get => this.background;
set => this.Set(() => this.background = value);
}
private Brush foreground;
public Brush Foreground
{
get => this.foreground;
set => this.Set(() => this.foreground = value);
}
private HorizontalAlignment horizontalContentAlignment = HorizontalAlignment.Right;
public HorizontalAlignment HorisontalContentAlignment
{
get => this.horizontalContentAlignment;
set => this.Set(() => this.horizontalContentAlignment = value);
}
public int ColSpan { get; set; } = 1;
public int RowSpan { get; set; } = 1;
}
}
@@ -0,0 +1,17 @@
namespace InspectionUI.ViewModels
{
using System.Windows;
internal class ItemsGridHeaderVM : ItemsGridCellVM
{
public ItemsGridHeaderVM() : base()
{
}
public GridLength Width { get; set; }
internal static readonly GridLength Auto = new GridLength(1, GridUnitType.Auto);
internal static readonly GridLength Star = new GridLength(1, GridUnitType.Star);
}
}
@@ -0,0 +1,84 @@
namespace InspectionUI.ViewModels
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class ItemsGridRowVM : VM, IEnumerable<ItemsGridCellVM>
{
private readonly IList<ItemsGridCellVM> cells;
public ItemsGridRowVM() : base()
{
this.cells = new List<ItemsGridCellVM>();
}
protected ItemsGridCellVM this[int index]
{
get
{
if (index >= this.cells.Count)
{
return default(ItemsGridCellVM);
}
return this.cells[index];
}
}
protected int LastIndex
{
get => this.Count() - 1;
}
public void Add(ItemsGridCellVM value)
{
this.cells.Add(value);
}
public void Clear()
{
foreach (var cell in this.cells)
{
cell.Dispose();
}
this.cells.Clear();
}
public IEnumerator<ItemsGridCellVM> GetEnumerator()
{
return this.cells.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
protected void Set<T>(Action propertySetterAction, T newValue, string format, int index)
{
this.Set(propertySetterAction);
this.Set(newValue, format, index);
}
protected void Set<T>(T value, string format, int index)
{
this.DispatcherInvoke(() =>
{
if (string.IsNullOrWhiteSpace(format))
{
format = "{0}";
}
this[index].Value = string.Format(format, value);
});
}
protected void Set(Action<ItemsGridCellVM> setter, int index)
{
this.DispatcherInvoke(() => setter(this[index]));
}
}
}
@@ -0,0 +1,50 @@
namespace InspectionUI.ViewModels
{
using System.Collections;
using System.Collections.Generic;
public abstract class ItemsGridVM : VM, IEnumerable<ItemsGridRowVM>
{
private readonly IList<ItemsGridRowVM> rows;
protected ItemsGridVM() : base()
{
this.rows = new List<ItemsGridRowVM>();
}
public IEnumerator<ItemsGridRowVM> GetEnumerator()
{
return this.rows.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
protected void Add(ItemsGridRowVM item)
{
this.rows.Add(item);
}
protected void Clear()
{
foreach (var item in this.rows)
{
item.Dispose();
}
this.rows.Clear();
}
protected int IndexOf(ItemsGridRowVM item)
{
return this.rows.IndexOf(item);
}
protected void Insert(int index, ItemsGridRowVM item)
{
this.rows.Insert(index, item);
}
}
}
@@ -0,0 +1,154 @@
namespace InspectionUI.ViewModels
{
using InspectionUI.Models;
using System;
using System.Windows.Input;
public class MainVM : VM
{
public MainVM() : base()
{
this.IsReloadEnabled = true;
this.Reload = new Command(this.ReloadCommand);
this.StartInspection = new Command(this.StartInspectionCommand);
this.CancelInspection = new Command(this.CancelInspectionCommand);
}
private int size;
public int Size
{
get => Math.Max(this.size - 5, 0);
set => this.Set(() => this.size = value + 5);
}
private string type;
public string Type
{
get => this.type;
set => this.Set(() => this.type = value);
}
private string suchnr;
public string SuchNr
{
get => this.suchnr;
set => this.Set(() => this.suchnr = value);
}
private bool keepCorrection;
public bool KeepCorrection
{
get => this.keepCorrection;
set => this.Set(() => this.keepCorrection = value);
}
private bool reloadEnabled;
public bool IsReloadEnabled
{
get => this.reloadEnabled;
private set => this.Set(() => this.reloadEnabled = value);
}
public ICommand Reload { get; }
private bool startInspectionEnabled;
public bool IsStartInspectionEnabled
{
get => this.startInspectionEnabled;
private set => this.Set(() => this.startInspectionEnabled = value);
}
public ICommand StartInspection { get; }
private bool cancelInspectionEnabled;
public bool IsCancelInspectionEnabled
{
get => this.cancelInspectionEnabled;
private set => this.Set(() => this.cancelInspectionEnabled = value);
}
public ICommand CancelInspection { get; }
private string errors;
public string Errors
{
get => this.errors;
private set => this.Set(() => this.errors = value);
}
private MetersPoolVM metersPoolVM;
public MetersPoolVM MetersPool
{
get => this.metersPoolVM;
private set => this.Set(() => this.metersPoolVM = value);
}
private void ReloadCommand()
{
this.EnableButtons(false);
this.Errors = default(string);
this.MetersPool = ServiceProvider.GetService<MetersPoolVM>();
if (!string.IsNullOrWhiteSpace(this.SuchNr))
{
this.MetersPool.LoadAuftrag(this.SuchNr);
}
else if (this.size >= 0 && !string.IsNullOrWhiteSpace(this.type))
{
this.MetersPool.LoadAuftrag((byte)this.size, this.type);
}
else
{
this.Errors = "FertigungauftragsNr oder Größe und Typ eingeben!";
}
if (string.IsNullOrWhiteSpace(this.Errors))
{
this.StartNewTask(() =>
{
this.Errors = "Connecting meters ...";
this.MetersPool.LoadMeters();
})
.ContinueWith(_ =>
{
this.Errors = default(string);
this.EnableButtons(true);
});
}
else
{
this.EnableButtons(true);
}
}
private void StartInspectionCommand()
{
this.StartNewTask(() =>
{
this.EnableButtons(false);
this.MetersPool.RunInspection(this.KeepCorrection);
this.IsCancelInspectionEnabled = false;
this.IsReloadEnabled = true;
});
}
private void CancelInspectionCommand()
{
this.StartNewTask(() =>
{
this.EnableButtons(false);
this.MetersPool.CancelInspection();
this.IsCancelInspectionEnabled = false;
this.IsReloadEnabled = true;
});
}
private void EnableButtons(bool enabled)
{
this.IsReloadEnabled = enabled;
this.IsStartInspectionEnabled = enabled;
this.IsCancelInspectionEnabled = !enabled;
}
}
}
@@ -0,0 +1,201 @@
namespace InspectionUI.ViewModels
{
using InspectionUI.Models;
using OmniPlus;
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Media;
public class MeterVM : ItemsGridRowVM
{
private readonly OmniMeter meter;
private int uinr = 0;
public MeterVM(OmniMeter meter) : base()
{
this.meter = meter;
this.Add(new ItemsGridHeaderVM { Value = $"{this.meter.SlotNr, 2}." });
this.Add(new ItemsGridCellVM());
this.Add(new ItemsGridCellVM());
this.Add(new ItemsGridCellVM());
var pruefpunkte = ServiceProvider
.GetService<OmniContext>()
.Auftrag
.Pruefpunkte
.Count;
for (int i = 0; i < pruefpunkte; i++)
{
this.Add(new ItemsGridCellVM());
this.Add(new ItemsGridCellVM());
this.Add(new ItemsGridCellVM());
}
this.Add(new ItemsGridCellVM());
this.MeterNr = this.meter.MeterNr;
this.SerialNr = this.meter.SerialNr;
}
private string meterId;
protected string MeterNr
{
get => this.meterId;
set => this.Set(() => this.meterId = value, value, "{0}", 1);
}
private int? serialNr;
protected int? SerialNr
{
get => this.serialNr;
set => this.Set(() => this.serialNr = value, value, "{0}", 2);
}
public override void Dispose()
{
try
{
this.meter.Dispose();
}
catch (Exception e)
{
this.meter.NotifyStateChanged($"[{DateTime.Now}] {e}");
}
base.Dispose();
}
public Task SaveMeterStateAsync(CancellationToken cancellationToken)
{
return this.StartNewTask(this.meter.SaveMeterState, cancellationToken);
}
public Task LoadTestRunAsync(CancellationToken cancellationToken)
{
return this.StartNewTask(this.meter.LoadTestRun, cancellationToken);
}
public Task InitializeInspectionAsync(bool keepCorrection, CancellationToken cancellationToken)
{
this.uinr = 0;
void InitializeInspection()
{
this.meter.InitializeForInspection(keepCorrection);
this.Set(this.meter.TestRun.CrrfBefore, "{0:0.0}", 3);
}
return this.StartNewTask(InitializeInspection, cancellationToken);
}
public Task StartCalibrationAsync(OmniPruefpunkt pp, CancellationToken cancellationToken)
{
this.uinr++;
void StartCalibration()
{
this.meter.StartCalibration((ushort)pp.Rotations, (ushort)pp.Duration);
this.ShowRestTime(pp.Duration, this.uinr * 3 + 1);
}
return this.StartNewTask(StartCalibration, cancellationToken);
}
public Task StopCalibrationAsync(OmniPruefpunkt pp, double refm3s, CancellationToken cancellationToken)
{
void StopCalibration()
{
var response = this.meter.StopCalibration(pp, refm3s);
var index = this.uinr * 3 + 1;
this.Set(response.Item2, "{0}", index);
this.Set(response.Item1, "{0:0.0000000000}", index + 1);
this.Set(response.Item3, "{0:0.00}", index + 2);
}
return this.StartNewTask(StopCalibration, cancellationToken);
}
public Task FinishInspectionAsync(CancellationToken cancellationToken)
{
void FinishInspection()
{
this.meter.FinishInspection();
var crrf = this.meter.TestRun.CrrfAfter;
var foreground = this.meter.TestRun.Succeeded == true
? Brushes.Green
: Brushes.Red;
this.Set(x => x.Foreground = foreground, this.LastIndex);
this.Set(crrf, "{0:0.0}", this.LastIndex);
this.uinr = 1;
foreach (var testedPP in this.meter.TestRun.TestedPoints)
{
var index = this.uinr * 3 + 1 + 2;
this.Set(testedPP.Acc, "{0:0.00}", index);
this.Set(x =>
{
foreground = testedPP.Succeeded == true
? Brushes.Green
: Brushes.Red;
x.Foreground = foreground;
}, index);
this.uinr++;
}
}
return this.StartNewTask(FinishInspection, cancellationToken);
}
private void ShowRestTime(int duration, int index)
{
var interval = 1000;
var timeout = duration * interval;
var waitHandle = new ManualResetEventSlim();
var timer = new System.Timers.Timer
{
AutoReset = true,
Enabled = true,
Interval = interval
};
void TimerElapsed(object _, ElapsedEventArgs _1)
{
duration--;
if (duration > 0)
{
this.Set(duration, "{0}", index);
}
}
timer.Elapsed += TimerElapsed;
timer.Start();
waitHandle.Wait(timeout);
timer.Stop();
waitHandle.Reset();
waitHandle.Wait(100);
timer.Elapsed -= TimerElapsed;
this.Set(default(string), "{0}", index);
}
}
}
@@ -0,0 +1,171 @@
namespace InspectionUI.ViewModels
{
using InspectionUI.Models;
using OmniPlus;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
public class MetersPoolVM : ItemsGridVM
{
private readonly OmniContext omniContext;
private CancellationTokenSource cancellationTokenSource;
private ReferenceMeterVM referenceMeter;
public MetersPoolVM(OmniContext omniContext) : base()
{
this.omniContext = omniContext;
}
public void CancelInspection()
{
this.cancellationTokenSource?.Cancel();
this.referenceMeter?.Stop();
}
public override void Dispose()
{
this.omniContext.Dispose();
this.Clear();
}
public void LoadMeters()
{
this.referenceMeter = ServiceProvider.GetService<ReferenceMeterVM>();
this.Add(this.referenceMeter);
this.omniContext
.LoadMetersAsync(Appsettings.COMPorts, Appsettings.PSNR)
.ContinueWith(_ =>
{
foreach (var meter in this.omniContext.Meters)
{
this.Add(new MeterVM(meter));
}
this.NotifyPropertyChanged();
});
}
public void RunInspection(bool keepCorrection = false, bool addCorrection = false)
{
this.cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = this.cancellationTokenSource.Token;
var tasks = new List<Task>();
var meters = this
.Select(x => x is MeterVM m ? m : null)
.Where(x => x != null)
.ToArray();
foreach (var meterVM in meters)
{
tasks.Add(meterVM.LoadTestRunAsync(cancellationToken));
}
this.ContinueWhenAll(tasks);
foreach (var meterVM in meters)
{
tasks.Add(meterVM.SaveMeterStateAsync(cancellationToken));
}
this.ContinueWhenAll(tasks);
foreach (var meterVM in meters)
{
tasks.Add(meterVM.InitializeInspectionAsync(keepCorrection, cancellationToken));
}
this.ContinueWhenAll(tasks);
var pruefpunkte = this.omniContext
.Auftrag
.Pruefpunkte;
foreach (var pp in pruefpunkte)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
this.referenceMeter.Start(pp);
if (cancellationToken.IsCancellationRequested)
{
break;
}
foreach (var meterVM in meters)
{
tasks.Add(meterVM.StartCalibrationAsync(pp, cancellationToken));
}
this.ContinueWhenAll(tasks);
if (cancellationToken.IsCancellationRequested)
{
break;
}
var refm3s = this.referenceMeter.GetFlow();
if (cancellationToken.IsCancellationRequested)
{
break;
}
foreach (var meterVM in meters)
{
tasks.Add(meterVM.StopCalibrationAsync(pp, refm3s, cancellationToken));
}
this.ContinueWhenAll(tasks);
if (cancellationToken.IsCancellationRequested)
{
break;
}
}
this.referenceMeter.Stop();
foreach (var meterVM in meters)
{
tasks.Add(meterVM.FinishInspectionAsync(cancellationToken));
}
this.ContinueWhenAll(tasks);
}
internal void LoadAuftrag(byte size, string type)
{
this.omniContext.LoadAuftrag(size, type);
this.UpdateItemsGridHeaders();
}
internal void LoadAuftrag(string suchNr)
{
this.omniContext.LoadAuftrag(suchNr);
this.UpdateItemsGridHeaders();
}
private void UpdateItemsGridHeaders()
{
this.DispatcherInvoke(() =>
{
this.Add(ServiceProvider.GetService<HeadersRowVM>());
this.Add(ServiceProvider.GetService<DefaultsHeaderRow>());
this.Add(ServiceProvider.GetService<DefaultsRowVM>());
});
}
}
}
@@ -0,0 +1,256 @@
namespace InspectionUI.ViewModels
{
using ExchangeHub;
using InspectionUI.Models;
using OmniPlus;
using OmniPlus.Inspection;
using System;
using System.Threading;
using System.Timers;
public class ReferenceMeterVM : ItemsGridRowVM
{
private readonly OmniContext omniContext;
private readonly ExchangeConnection signarR;
private int ppnr;
private bool cancel;
public ReferenceMeterVM(OmniContext omniContext, ExchangeConnection signarR) : base()
{
this.omniContext = omniContext;
this.signarR = signarR;
this.signarR.StateChanged += this.SignarR_StateChanged;
this.signarR.Connect(Appsettings.HubURL);
this.ppnr = 1;
this.LoadHeaders();
}
internal void Start(OmniPruefpunkt pp)
{
this.ppnr += 3;
this.cancel = false;
this.StartFlow(pp);
this.StartRZ(pp);
}
private void StartFlow(OmniPruefpunkt pp)
{
var interval = 1000;
var timeout = 5;// 00;
var volume = default(double);
var waitHandle = new ManualResetEventSlim();
var timer = new System.Timers.Timer
{
AutoReset = true,
Enabled = true,
Interval = interval,
};
void FlowStarted(double value, string _)
{
volume = value;
timer.Stop();
waitHandle.Set();
}
void TimerElapsed(object _, ElapsedEventArgs _1)
{
if (timeout < 0 || cancel)
{
timeout = 0;
timer.Stop();
waitHandle.Set();
}
else
{
this.Set(timeout, "... {0}", this.ppnr + 1);
}
timeout--;
}
timer.Elapsed += TimerElapsed;
this.signarR.StartFlow += FlowStarted;
timer.Start();
this.signarR.SendStartFlow(pp.FlowM3H);
waitHandle.Wait(timeout * interval);
waitHandle.Reset();
this.signarR.StartFlow -= FlowStarted;
timer.Elapsed -= TimerElapsed;
waitHandle.Wait(1000);
this.Set(volume, "{0:0.000}", this.ppnr + 1);
}
private void StartRZ(OmniPruefpunkt pp)
{
var interval = 1000;
var timeout = 6;// 0;
var seconds = default(double);
var waitHandle = new ManualResetEventSlim();
var timer = new System.Timers.Timer
{
AutoReset = true,
Enabled = true,
Interval = interval,
};
void RZStarted(int value, string _)
{
seconds = value;
timer.Stop();
waitHandle.Set();
}
void TimerElapsed(object _, ElapsedEventArgs _1)
{
if (timeout < 0 || cancel)
{
timeout = 0;
timer.Stop();
waitHandle.Set();
}
else
{
this.Set(timeout, "... {0}", this.ppnr);
}
timeout--;
}
timer.Elapsed += TimerElapsed;
this.signarR.StartReferenceMessurement += RZStarted;
timer.Start();
this.signarR.SendStartReferenceMessurement(pp.Duration);
waitHandle.Wait(timeout * interval);
waitHandle.Reset();
this.signarR.StartReferenceMessurement -= RZStarted;
timer.Elapsed -= TimerElapsed;
waitHandle.Wait(1000);
this.Set(seconds, ".../{0:0.0}", this.ppnr);
}
internal double GetFlow()
{
var interval = 1000;
var timeout = 6;// 0;
var referenceV = 0D;
var waitHandle = new ManualResetEventSlim();
var timer = new System.Timers.Timer
{
AutoReset = true,
Enabled = true,
Interval = interval,
};
void ReceiveFlow(double value, string _)
{
timeout = 0;
referenceV = value;
timer.Stop();
waitHandle.Set();
}
void TimerElapsed(object _, ElapsedEventArgs _1)
{
if (timeout < 0 || cancel)
{
timeout = 0;
timer.Stop();
waitHandle.Set();
}
else
{
this.Set(timeout, "... {0}", this.ppnr + 2);
}
timeout--;
}
timer.Elapsed += TimerElapsed;
this.signarR.StopReferenceMessurement += ReceiveFlow;
timer.Start();
this.signarR.SendStopReferenceMessurement();
waitHandle.Wait(timeout * interval);
waitHandle.Reset();
OmniPlusFormulas.OutDebugM3S(ref referenceV);
this.signarR.StopReferenceMessurement -= ReceiveFlow;
timer.Elapsed -= TimerElapsed;
waitHandle.Wait(1000);
this.Set(referenceV, "{0:0.0000000000}", this.ppnr + 1);
this.Set(referenceV == 0 ? 0 : 100, "{0:0.00}", this.ppnr + 2);
return referenceV;
}
internal void Stop()
{
this.cancel = true;
this.signarR.SendStopFlow();
}
public override void Dispose()
{
try
{
this.signarR.SendStopFlow();
this.signarR.Disconnect();
}
catch (Exception e)
{
AppLogger.Log($"[...] {e}");
}
base.Dispose();
}
private void SignarR_StateChanged(string value, string groupName)
{
AppLogger.Log($"[{groupName}] {value}");
}
private void LoadHeaders()
{
this.DispatcherInvoke(() =>
{
this.Add(new ItemsGridHeaderVM());
this.Add(new ItemsGridHeaderVM { Value = "RZ:" });
this.Add(new ItemsGridHeaderVM());
this.Add(new ItemsGridHeaderVM());
foreach (var _ in this.omniContext.Pruefpunkte)
{
this.Add(new ItemsGridHeaderVM());
this.Add(new ItemsGridHeaderVM());
this.Add(new ItemsGridHeaderVM());
}
this.Add(new ItemsGridHeaderVM());
});
}
}
}
@@ -0,0 +1,154 @@
namespace InspectionUI.ViewModels
{
using InspectionUI.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
public abstract class VM : INotifyPropertyChanged, IDisposable
{
private static readonly Dispatcher dispatcher = Application.Current.Dispatcher;
protected VM()
{
App.Exiting += this.Dispose;
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void Dispose()
{
App.Exiting -= this.Dispose;
}
protected void ContinueWhenAll(List<Task> tasks, Action continuationCallback = null)
{
if (tasks is null || tasks.Count == 0)
{
return;
}
Task.Factory
.ContinueWhenAll(tasks.ToArray(), _tasks =>
{
foreach (var task in _tasks)
{
if (task.Exception != null)
{
AppLogger.Log(task.Exception);
}
}
tasks.Clear();
continuationCallback?.Invoke();
})
.Wait();
}
protected void NotifyPropertyChanged()
{
if (this.PropertyChanged != null)
{
dispatcher.Invoke(new Action(() =>
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(default(string)));
}));
}
}
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
if (this.PropertyChanged != null)
{
dispatcher.Invoke(new Action(() =>
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}));
}
}
protected void DispatcherInvoke(Action action)
{
dispatcher.Invoke(action);
}
protected void Set(Action setExpression, [CallerMemberName] string property = "")
{
this.DispatcherInvoke(setExpression);
this.NotifyPropertyChanged(property);
}
protected Task StartNewTask(Action action, CancellationToken cancellationToken = default(CancellationToken))
{
return Task
.Factory
.StartNew(action, cancellationToken)
.ContinueWith(task =>
{
if (task.Exception != null)
{
AppLogger.Log(task.Exception);
}
}, cancellationToken);
}
protected class Command : ICommand
{
private readonly Action executable;
public Command(Action executable)
{
this.executable = executable;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object _)
{
return this.executable != null;
}
public void Execute(object _)
{
this.executable?.Invoke();
}
}
protected class Command<T> : ICommand
{
private readonly Action<T> executable;
public Command(Action<T> executable)
{
this.executable = executable;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object _)
{
return this.executable != null;
}
public void Execute(object parameter)
{
this.executable?.Invoke(parameter is T t ? t : default(T));
}
}
}
}
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net481" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" requireReinstallation="true" />
</packages>
@@ -0,0 +1,29 @@
namespace OmniPlus.Connections
{
internal sealed class OmniIrdaEncoder : SerialDataEncoder
{
public override bool TryDecode(byte[] data, out byte[] message, out int start, out int length)
{
message = default(byte[]);
if (data.FromIrdaMessage(out byte[] payload, out start, out length))
{
if (payload.FromUI1236Message(out message, out start, out length))
{
return true;
}
}
return false;
}
public override bool TryEncode(byte[] data, out byte[] message)
{
message = data
.ToUI1236Message()
.ToIrdaMessage();
return message != null && message.Length > 0;
}
}
}
@@ -0,0 +1,51 @@
namespace OmniPlus.Connections
{
using System.Threading;
internal sealed class OmniIrdaStream : SerialDataStream
{
private readonly ManualResetEventSlim waitHandle;
public OmniIrdaStream(SerialDataEncoder encoder, SerialPortSettings settings) : base(encoder, settings)
{
this.waitHandle = new ManualResetEventSlim();
}
public override byte[] Send(params byte[] message)
{
var response = new byte[0];
var received = false;
void DataReceived(byte[] data)
{
response = data;
received = true;
this.waitHandle.Set();
}
this.DataReceived += DataReceived;
this.StartListening();
for (int i = 0; i < 3 && !received; i++)
{
this.WritePlain(1, 1, 1, 1);
this.waitHandle.Reset();
this.waitHandle.Wait(1);
this.WriteEncoded(message);
this.waitHandle.Reset();
this.waitHandle.Wait(3000);
}
this.StopListening();
this.DataReceived -= DataReceived;
return response;
}
}
}
@@ -0,0 +1,22 @@
namespace OmniPlus.Connections
{
internal class OmniUniProEncoder : SerialDataEncoder
{
public override bool TryDecode(byte[] data, out byte[] message, out int start, out int length)
{
return data.FromUniProMessage(out message, out start, out length);
}
public override bool TryEncode(byte[] data, out byte[] message)
{
message = new byte[0];
if (data != null && data.Length > 0)
{
message = data.ToUniProMessage();
}
return message != null && message.Length > 0;
}
}
}
@@ -0,0 +1,46 @@
namespace OmniPlus.Connections
{
using System.Threading;
internal class OmniUniProStream : SerialDataStream
{
private readonly ManualResetEventSlim waitHandle;
public OmniUniProStream(SerialDataEncoder encoder, SerialPortSettings settings) : base(encoder, settings)
{
this.waitHandle = new ManualResetEventSlim();
}
public override byte[] Send(params byte[] message)
{
var response = new byte[0];
var received = false;
void DataReceived(byte[] data)
{
response = data;
received = true;
this.waitHandle.Set();
}
this.DataReceived += DataReceived;
this.StartListening();
for (int i = 0; i < 3 && !received; i++)
{
this.WriteEncoded(message);
this.waitHandle.Reset();
this.waitHandle.Wait(3000);
}
this.StopListening();
this.DataReceived -= DataReceived;
return response;
}
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Connections
{
internal abstract class SerialDataEncoder
{
public abstract bool TryEncode(byte[] data, out byte[] message);
public abstract bool TryDecode(byte[] data, out byte[] message, out int start, out int length);
}
}
@@ -0,0 +1,409 @@
namespace OmniPlus.Connections
{
using System;
public static class SerialDataExtensions
{
public const int BYTE_BITS = 8;
public const byte OxOO = 0x00;
public const byte OxO1 = 0x01;
public const byte OxO2 = 0x02;
public const byte OxO3 = 0x03;
public const byte UNIPRO_START = 0x53;
public const byte UNIPRO_PC2REG = 0x57;
public const byte UNIPRO_REG2PC = 0x52;
public const byte UNIPRO_STOP = 0x0D;
public const byte UNIPRO_MIN_LENGTH = 4;
public const byte UI1236_START = 0x0D;
public const byte UI1236_LEN_INDEX = 1;
public const byte UI1236_DATA_INDEX = 3;
public const byte UI1236_MIN_LENGTH = 5;
public const byte UI1236_HEAD_LENGTH = 3;
public const byte IRDA_START = 0x9B;
public const byte IRDA_PING = 0x82;
public const byte IRDA_PC2REG = 0x33;
public const byte IRDA_REG2PC = 0x43;
public const byte IRDA_LEN_INDEX = 2;
public const byte IRDA_DATA_INDEX = 3;
public const byte IRDA_MIN_LENGTH = 5;
public const byte IRDA_CRC_LENGTH = 2;
/// <summary>
/// <para>UI1236 structure:</para>
/// <para> 0. 0x0D - Start byte</para>
/// <para> 1. .... - Length: max. 254</para>
/// <para> 2. .... - Control byte</para>
/// <para>3+n. .... - Payload</para>
/// <para>n-2. .... - Checksum 0 </para>
/// <para>n-1. .... - Checksum 1 </para>
/// </summary>
public static byte[] ToUI1236Message(this byte[] bytes)
{
var message = new byte[0];
if (bytes is null)
{
return message;
}
var bytesLength = bytes.Length;
if (bytesLength == 0)
{
return message;
}
var messageLength = bytes.Length + UI1236_MIN_LENGTH;
messageLength += messageLength % OxO2;
var index = OxOO;
message = new byte[messageLength];
message[index++] = UI1236_START;
message[index++] = (byte)(bytesLength + UI1236_HEAD_LENGTH);
UI1236Control control = OxOO;
control.ReturnResponse = true;
message[index++] = control;
bytes.CopyTo(message, index);
var checksum = message.CalculateCheckSUM(message.Length - OxO2);
var checksumIndex = bytesLength + UI1236_HEAD_LENGTH;
message[checksumIndex++] = checksum[OxO1];
message[checksumIndex++] = checksum[OxOO];
return message;
}
/// <summary>
/// <para>UniPro structure:</para>
/// <para> 0. .... - Start byte</para>
/// <para> 1. .... - Direction</para>
/// <para> 2. .... - Length</para>
/// <para> .. .... - Payload</para>
/// <para>n-1. .... - Stop byte</para>
/// </summary>
public static byte[] ToUniProMessage(this byte[] bytes)
{
var messageLength = (byte)(bytes.Length + UNIPRO_MIN_LENGTH);
var message = new byte[messageLength];
var index = OxOO;
message[index++] = UNIPRO_START;
message[index++] = UNIPRO_PC2REG;
message[index++] = messageLength;
message[messageLength - OxO1] = UNIPRO_STOP;
bytes.CopyTo(message, index);
return message;
}
/// <summary>
/// <para>UniPro structure:</para>
/// <para> 0. .... - Start byte</para>
/// <para> 1. .... - Direction</para>
/// <para> 2. .... - Length</para>
/// <para> .. .... - Payload</para>
/// <para>n-1. .... - Stop byte</para>
/// </summary>
public static bool FromUniProMessage(this byte[] bytes, out byte[] message, out int start, out int length)
{
message = default(byte[]);
length = default(int);
start = default(int);
if (bytes is null)
{
return false;
}
var bytesLength = bytes.Length;
while (start < bytesLength)
{
start = Array.IndexOf(bytes, UNIPRO_REG2PC) - 1;
if (start < 0 || bytes[start] == UNIPRO_START)
{
break;
}
start += 2;
}
if (start < 0)
{
return false;
}
start += 2;
if (start >= bytesLength)
{
return false;
}
length = bytes[start] - UNIPRO_MIN_LENGTH;
if (start + length >= bytesLength)
{
return false;
}
start += 1;
message = new byte[length];
Buffer.BlockCopy(bytes, start, message, 0, length);
return true;
}
/// <summary>
/// <para>Irda structure:</para>
/// <para> 0. .... - Start byte</para>
/// <para> 1. .... - Direction</para>
/// <para> 2. .... - Length / 2</para>
/// <para>3+n. .... - Payload</para>
/// <para>n-3. .... - aligned byte</para>
/// <para>n-2. .... - CRC16 0 </para>
/// <para>n-1. .... - CRC16 1 </para>
/// </summary>
public static byte[] ToIrdaMessage(this byte[] bytes)
{
var message = new byte[0];
if (bytes is null)
{
return message;
}
var bytesLength = bytes.Length;
if (bytesLength == 0)
{
return message;
}
var messageLength = bytesLength;
messageLength += messageLength % OxO2;
var index = OxOO;
message = new byte[messageLength + IRDA_MIN_LENGTH];
message[index++] = IRDA_START;
message[index++] = IRDA_PC2REG;
message[index++] = (byte)(messageLength / OxO2);
bytes.CopyTo(message, index);
var _length = message.Length;
var crc16 = message.CalculateCRC8408(1, _length - IRDA_CRC_LENGTH);
message[_length - OxO2] = crc16[OxOO];
message[_length - OxO1] = crc16[OxO1];
return message;
}
/// <summary>
/// <para>Irda structure:</para>
/// <para> 0. .... - Start byte</para>
/// <para> 1. .... - Direction</para>
/// <para> 2. .... - Length / 2</para>
/// <para>3+n. .... - Payload</para>
/// <para>n-3. .... - aligned byte</para>
/// <para>n-2. .... - CRC16 0 </para>
/// <para>n-1. .... - CRC16 1 </para>
/// </summary>
public static bool FromIrdaMessage(this byte[] bytes, out byte[] message, out int start, out int length)
{
message = default(byte[]);
length = default(int);
start = default(int);
if (bytes is null)
{
return false;
}
var bytesLength = bytes.Length;
while (start < bytesLength)
{
start = Array.IndexOf(bytes, IRDA_REG2PC, start) - 1;
if (start < 0 || bytes[start] == IRDA_START)
{
break;
}
start += 2;
}
if (start < 0)
{
return false;
}
start += 2;
if (start >= bytesLength)
{
return false;
}
length = bytes[start] * 2;
if (start + length >= bytesLength)
{
return false;
}
start += 1;
message = new byte[length];
Buffer.BlockCopy(bytes, start, message, 0, length);
return true;
}
/// <summary>
/// <para>UI1236 structure:</para>
/// <para> 0. 0x0D - Start byte</para>
/// <para> 1. .... - Length: max. 254</para>
/// <para> 2. .... - Control byte</para>
/// <para>3+n. .... - Payload</para>
/// <para>n-2. .... - Checksum 0 </para>
/// <para>n-1. .... - Checksum 1 </para>
/// </summary>
public static bool FromUI1236Message(this byte[] bytes, out byte[] message, out int start, out Int32 length)
{
message = default(byte[]);
length = default(int);
start = default(int);
if (bytes is null)
{
return false;
}
start = Array.IndexOf(bytes, UI1236_START);
if (start < 0)
{
return false;
}
start += 1;
if (start >= bytes.Length)
{
return false;
}
length = bytes[start] - UI1236_HEAD_LENGTH;
if (length <= 0)
{
return false;
}
start += 2;
if (start + length >= bytes.Length)
{
return false;
}
message = new byte[length];
Buffer.BlockCopy(bytes, start, message, 0, length);
return true;
}
public static byte[] CalculateCRC8408(this byte[] message, int start, int length)
{
var crc = 0xFFFF;
for (int x = start; x < length; x++)
{
crc ^= 0x00FF & message[x];
for (int i = 8; i > OxOO; i--)
{
if ((crc & 0x0001) != OxOO)
{
crc = (crc >> OxO1) ^ 0x8408;
}
else
{
crc >>= OxO1;
}
}
}
crc = ~crc;
return BitConverter.GetBytes(crc);
}
public static byte[] CalculateCheckSUM(this byte[] bytes, int length)
{
ushort checksum = OxOO;
for (int i = OxOO; i < length; i++)
{
checksum += bytes[i];
}
return BitConverter.GetBytes(checksum);
}
public static byte[] CalculateCRC16(this byte[] data, int start, int length)
{
ushort crc_result = 0xFFFF;
ushort ui_index = (ushort)start;
int maxLength = length + start;
byte test;
byte current;
if (data.Length >= maxLength)
{
while (ui_index < maxLength)
{
current = data[ui_index];
ui_index++;
for (byte h = 0; h < 8; h++)
{
test = 0;
if ((crc_result & 0x8000) != 0)
{
test = 0x80;
}
crc_result <<= 1;
if (((current & 0x80) ^ test) != 0)
{
crc_result ^= 0x1021;
}
current <<= 1;
}
maxLength = length + start;
}
}
return BitConverter.GetBytes(crc_result);
}
}
}
@@ -0,0 +1,159 @@
namespace OmniPlus.Connections
{
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
internal abstract class SerialDataStream : SerialPortStream
{
private readonly ManualResetEventSlim waitHandle;
private readonly SerialDataEncoder encoder;
private readonly List<byte> buffer;
private CancellationTokenSource cancellationTokenSource;
private CancellationToken cancellationToken;
private Task readingTask;
protected SerialDataStream(SerialDataEncoder encoder, SerialPortSettings settings) : base(settings)
{
this.encoder = encoder;
this.buffer = new List<byte>();
this.waitHandle = new ManualResetEventSlim();
}
protected event Action<byte[]> DataReceived;
public override void Close()
{
try
{
if (this.cancellationTokenSource != null)
{
this.cancellationTokenSource.Cancel();
}
}
catch (Exception e)
{
this.NotifyStateChanged($"--- {e}");
}
base.Close();
}
public override void Open()
{
base.Open();
try
{
this.StartReading();
}
catch (Exception e)
{
this.NotifyStateChanged($"--- {e}");
}
}
protected void StartListening()
{
try
{
this.buffer.Clear();
this.waitHandle.Set();
}
catch (Exception e)
{
this.NotifyStateChanged($"--- {e}");
}
}
protected void StopListening()
{
try
{
this.waitHandle.Reset();
this.buffer.Clear();
}
catch (Exception e)
{
this.NotifyStateChanged($"--- {e}");
}
}
protected void WriteEncoded(params byte[] bytes)
{
try
{
if (this.encoder.TryEncode(bytes, out byte[] message))
{
this.Write(message, 0, message.Length);
this.NotifyStateChanged($">>> {BitConverter.ToString(bytes)}");
}
}
catch (Exception e)
{
this.NotifyStateChanged($"--- {e}");
}
}
protected void WritePlain(params byte[] bytes)
{
try
{
this.Write(bytes, 0, bytes.Length);
}
catch (Exception e)
{
this.NotifyStateChanged($"--- {e}");
}
}
private void ReadingTaskHandler(object state)
{
if (state is SerialDataStream serialDataStream)
{
while (serialDataStream.IsOpen)
{
serialDataStream.waitHandle.Wait();
var length = serialDataStream.BytesToRead;
if (length > 0)
{
var buffer = new byte[length];
serialDataStream.Read(buffer, 0, length);
serialDataStream.buffer.AddRange(buffer);
var data = serialDataStream.buffer.ToArray();
if (serialDataStream.encoder.TryDecode(data, out byte[] message, out int start, out int _))
{
serialDataStream.DataReceived?.Invoke(message);
serialDataStream.NotifyStateChanged($"<<< {BitConverter.ToString(message)}");
}
}
}
}
}
private void StartReading()
{
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
this.readingTask = Task.Factory.StartNew(this.ReadingTaskHandler, this, this.cancellationToken);
this.readingTask.ContinueWith(task =>
{
if (task.Exception != null)
{
this.NotifyStateChanged($"--- {task.Exception}");
}
this.StartReading();
});
}
}
}
@@ -0,0 +1,17 @@
namespace OmniPlus.Connections
{
using System.IO.Ports;
internal class SerialPortSettings
{
public int BaudRate { get; set; }
public int DataBits { get; set; }
public Parity Parity { get; set; }
public string PortName { get; set; }
public StopBits StopBits { get; set; }
}
}
@@ -0,0 +1,137 @@
namespace OmniPlus.Connections
{
using System;
using System.IO.Ports;
public delegate void StateChanged(object state);
internal abstract class SerialPortStream
{
protected SerialPort serialPort;
private readonly SerialPortSettings settings;
protected SerialPortStream(SerialPortSettings settings)
{
if (settings is null)
{
throw new ArgumentNullException($"{nameof(SerialPortSettings)} are required.");
}
this.settings = settings;
}
public event StateChanged StateChanged;
public int BytesToRead
{
get
{
if (this.IsOpen)
{
return this.serialPort.BytesToRead;
}
return default(int);
}
}
public bool IsOpen
{
get
{
if (this.serialPort is null)
{
return false;
}
return this.serialPort.IsOpen;
}
}
public virtual void Close()
{
try
{
if (this.serialPort != null)
{
this.serialPort.Close();
this.serialPort.Dispose();
this.serialPort = null;
this.NotifyStateChanged($"--- Disconnected: {this}");
}
}
catch (Exception e)
{
this.NotifyStateChanged($"--- {e}");
}
}
public virtual void Open()
{
try
{
this.serialPort = new SerialPort
{
BaudRate = this.settings.BaudRate,
DataBits = this.settings.DataBits,
Parity = this.settings.Parity,
PortName = this.settings.PortName,
StopBits = this.settings.StopBits,
DtrEnable = true
};
this.serialPort.Open();
this.NotifyStateChanged($"--- Connected: {this}");
}
catch (Exception e)
{
this.NotifyStateChanged($"--- {e}");
}
}
public override string ToString()
{
if (this.serialPort is null)
{
return $"{this.settings.PortName}, " +
$"{this.settings.BaudRate}, " +
$"{this.settings.DataBits}, " +
$"{this.settings.Parity}, " +
$"{this.settings.StopBits}";
}
else
{
return $"{this.serialPort.PortName}, " +
$"{this.serialPort.BaudRate}, " +
$"{this.serialPort.DataBits}, " +
$"{this.serialPort.Parity}, " +
$"{this.serialPort.StopBits}";
}
}
public abstract byte[] Send(params byte[] message);
protected void NotifyStateChanged(object state)
{
this.StateChanged?.Invoke(state);
}
protected void Read(byte[] bytes, int start, int length)
{
this.serialPort.Read(bytes, start, length);
}
protected void Write(byte[] bytes, int start, int length)
{
var lock_object = new object();
lock (lock_object)
{
this.serialPort.Write(bytes, 0, length);
}
}
}
}
@@ -0,0 +1,66 @@
namespace OmniPlus.Connections
{
internal class UI1236Control
{
private readonly byte[] bits;
private UI1236Control(byte[] bits)
=> this.bits = bits;
public bool E0Encryption => this.bits[0] == 1;
public bool E1Encryption => this.bits[1] == 1;
public bool E2Encryption => this.bits[2] == 1;
public bool ReturnResponse
{
get => this.bits[3] == 1;
set => this.bits[3] = (byte)(value ? 1 : 0);
}
public bool NFNetwork => this.bits[4] == 1;
public bool MultipleCommands
{
get => this.bits[5] == 1;
set => this.bits[5] = (byte)(value ? 1 : 0);
}
public bool LongControl
{
get => this.bits[6] == 1;
set => this.bits[6] = (byte)(value ? 1 : 0);
}
public bool MultipleFrames
{
get => this.bits[7] == 1;
set => this.bits[7] = (byte)(value ? 1 : 0);
}
public static implicit operator UI1236Control(byte controlByte)
{
var bits = new byte[8];
for (int i = 0; i < 8; i++)
{
bits[i] = (byte)((controlByte >> i) & 1);
}
return new UI1236Control(bits);
}
public static implicit operator byte (UI1236Control control)
{
var @byte = default(byte);
for (int i = 0; i < 8; i++)
{
@byte ^= (byte)(control.bits[i] << i);
}
return @byte;
}
}
}
@@ -0,0 +1,76 @@
namespace OmniPlus.Features
{
using static System.Text.Encoding;
public class ASCIIString : FeatureRequest
{
protected const char NULL = '\0';
public ASCIIString(int length) : base(length)
{
}
public ASCIIString(string value, int length)
: base(length)
=> this.Value = $"{value}";
public ASCIIString(byte[] response, int length) : base(response, length)
{
}
public string Value
{
get => this.GetValue();
set => this.SetValue(value);
}
public void ToASCIIString(byte[] buffer, int start, int end)
{
var value = string.Empty;
var length = buffer.Length;
while (start < length && start <= end)
{
value += (char)buffer[start];
start++;
}
this.SetValue(value);
}
private string GetValue()
{
if (this.bytes?.Length > 0)
{
return ASCII
.GetString(this.bytes)
.Trim('\0');
}
return default(string);
}
private void SetValue(string value)
{
for (int i = 0; i < this.bytes.Length; i++)
{
this.bytes[i] = 0;
}
if (!string.IsNullOrWhiteSpace(value))
{
var buffer = ASCII.GetBytes(value);
var bufferLength = buffer.Length;
var bufferIndex = 0;
var i = 1;
while (i < this.length && i < bufferLength)
{
this.bytes[i++] = buffer[bufferIndex++];
}
}
}
}
}
@@ -0,0 +1,92 @@
namespace OmniPlus.Features
{
using System;
public class Alarm : FeatureRequest
{
const int LENGTH = 12;
public Alarm() : base(LENGTH)
{
}
public Alarm(byte[] response) : base(response, LENGTH)
{
}
public byte DeviceId
{
get => this.bytes[0];
protected set => this.bytes[0] = value;
}
public byte AlarmType
{
get => this.bytes[1];
protected set => this.bytes[1] = value;
}
public byte AlarmId
{
get => this.bytes[2];
protected set => this.bytes[2] = value;
}
public byte Channel
{
get => this.bytes[3];
protected set => this.bytes[3] = value;
}
/// <summary>
/// Rate = 0.25 * 1/60 * 1/1 = .0041666667 Gal/sec which converts into a Float32 of into 0x3B888889.
/// </summary>
public float FlowRateGal
{
get => BitConverter.ToSingle(this.bytes, 4);
set => BitConverter.GetBytes(value * (1 / 60) * (1 / 1)).CopyTo(this.bytes, 4);
}
/// <summary>
/// 0x00015180 (86400) seconds, which is 24 hours.
/// </summary>
public uint TimeLimit
{
get => BitConverter.ToUInt32(this.bytes, 8);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 8);
}
}
public class LeakAlarm : Alarm
{
public LeakAlarm()
{
this.DeviceId = 0x00;
this.AlarmType = 0x04;
this.AlarmId = 0x01;
this.Channel = 0x00;
}
}
public class HighFlowAlarm : Alarm
{
public HighFlowAlarm()
{
this.DeviceId = 0x00;
this.AlarmType = 0x04;
this.AlarmId = 0x02;
this.Channel = 0x00;
}
}
public class ReverseFlowAlarm : Alarm
{
public ReverseFlowAlarm()
{
this.DeviceId = 0x00;
this.AlarmType = 0x05;
this.AlarmId = 0x04;
this.Channel = 0x00;
}
}
}
@@ -0,0 +1,57 @@
namespace OmniPlus.Features
{
using System;
public class AlarmSettings : FeatureRequest
{
const int LENGTH = 28;
public AlarmSettings() : base(LENGTH)
{
}
public AlarmSettings(byte[] response) : base(response, LENGTH)
{
}
public byte SensorVAndUsrAlarmsCount
{
get => this.bytes[0];
}
public byte ConfigVAndSequence
{
get => this.bytes[1];
}
public byte[] BitMask
{
get => this.bytes.Subarray(2, 3);
}
public byte PersistenceInDays
{
get => this.bytes[5];
}
public byte IdAndState
{
get => this.bytes[6];
}
public uint SecondsTriggered
{
get => BitConverter.ToUInt32(this.bytes, 7);
}
public uint SecondsEnded
{
get => BitConverter.ToUInt32(this.bytes, 11);
}
public string TypeAndData
{
get => BitConverter.ToString(this.bytes, 15, 13);
}
}
}
@@ -0,0 +1,49 @@
namespace OmniPlus.Features
{
public class AlarmsState : FeatureResponse
{
const int LENGTH = 27;
private readonly byte[] bytesI;
private readonly byte[] bytesII;
public AlarmsState(byte[] response) : base(response, LENGTH)
{
this.bytesI = this.I.Reverse().GetBits();
this.bytesII = this.II.Reverse().GetBits();
}
public byte Registers => this.bytes[0];
public byte[] I => this.bytes.Subarray(1, 6);
public byte[] II => this.bytes.Subarray(7, 6);
public byte III => this.bytes[13];
public byte IV => this.bytes[14];
public byte[] V => this.bytes.Subarray(15, 4);
public byte[] VI => this.bytes.Subarray(19, 2);
public byte[] VII => this.bytes.Subarray(21, 2);
public byte[] VIII => this.bytes.Subarray(23, 4);
public bool PreEnabledInactive
=> this.bytesI[8] + this.bytesI[9] == 1
&& this.bytesI[16] + this.bytesI[17] == 1
&& this.bytesI[24] + this.bytesI[25] == 1
&& this.bytesI[30] + this.bytesI[31] == 1
&& this.bytesI[32] + this.bytesI[33] == 1
&& this.bytesI[34] + this.bytesI[35] == 1
&& this.bytesI[42] + this.bytesI[43] == 1
&& this.bytesI[46] + this.bytesI[47] == 1;
public bool UsrEnabled
=> this.bytesI[38] + this.bytesI[39] == 1
&& this.bytesI[42] + this.bytesI[43] == 1
&& this.bytesI[44] + this.bytesI[45] == 1;
}
}
@@ -0,0 +1,29 @@
namespace OmniPlus.Features
{
using System;
public class BatteryVoltage : FeatureRequest
{
const int LENGTH = 6;
public BatteryVoltage() : base(LENGTH)
{
}
public BatteryVoltage(byte[] response) : base(response, LENGTH)
{
}
public ushort Volts
{
get => BitConverter.ToUInt16(this.bytes, 0);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 0);
}
public uint ADCCount
{
get => BitConverter.ToUInt32(this.bytes, 2);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 2);
}
}
}
@@ -0,0 +1,27 @@
namespace OmniPlus.Features
{
/// <summary>
/// Build Information string must be at most 14 characters long. There are no restrictions on character type.
/// Command is not available after factory seal.
/// </summary>
public class BuildInfo : ASCIIString
{
const int LENGTH = 16;
public BuildInfo() : base(LENGTH)
{
}
public BuildInfo(byte[] response) : base(response, LENGTH)
{
}
public BuildInfo(string value) : base(value, LENGTH)
{
}
public static implicit operator BuildInfo(string value)
=> new BuildInfo { Value = value };
}
}
@@ -0,0 +1,48 @@
namespace OmniPlus.Features
{
using System;
public class ChamberCalibrationRequest : FeatureRequest
{
public const byte ACTIVATE_TEST = 0x00;
public const byte REQUEST_RESULTS = 0x01;
const int LENGTH = 5;
public ChamberCalibrationRequest() : base(LENGTH)
{
}
public ChamberCalibrationRequest(byte[] response) : base(response, LENGTH)
{
}
/// <summary>
/// 0 Activate Factory Calibration Test
/// 1 Request Factory Calibration Test Results
/// </summary>
public byte Control
{
get => this.bytes[0];
set => this.bytes[0] = value;
}
/// <summary>
/// Request: Number of Rotations to collect. (not required if Requesting Calibration results) (Limited to 1 to 5000 rotations)
/// </summary>
public ushort Rotations
{
get => BitConverter.ToUInt16(this.bytes, 1);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 1);
}
/// <summary>
/// Request: Maximum Time command is supposed to take to execute - 1 to 3600 Seconds.
/// </summary>
public ushort Duration
{
get => BitConverter.ToUInt16(this.bytes, 3);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 3);
}
}
}
@@ -0,0 +1,56 @@
namespace OmniPlus.Features
{
using System;
public class ChamberCalibrationResponse : FeatureRequest
{
public const byte TEST_ACTIVATED = 0x00;
public const byte TEST_FAILED = 0x01;
public const byte TEST_COMPLETED = 0x02;
const int LENGTH = 7;
public ChamberCalibrationResponse() : base(LENGTH)
{
}
public ChamberCalibrationResponse(byte[] response) : base(response, LENGTH)
{
}
/// <summary>
/// 0 Test Activation Successful
/// 1 Test Failed (Timeout)
/// 2 Test Successfully Completed
/// </summary>
public byte Control
{
get => this.bytes[0];
set => this.bytes[0] = value;
}
/// <summary>
/// Response: Number of rotations collected
/// On Test Activation, this field echoes the number of rotations requested.
/// On Test Failed and Test Successfully Completed, returns the number of rotations collected.
/// </summary>
public ushort Rotations
{
get => BitConverter.ToUInt16(this.bytes, 1);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 1);
}
/// <summary>
/// Response: Total Time it took to collect the indicated rotations. Each count is equal to 30.5176us.
/// On Test Activation Successful, returns number of seconds test is allowed to take.
/// On Test Failed, this field will show 0 indicating that the tested failed.
/// </summary>
public uint Duration
{
get => BitConverter.ToUInt32(this.bytes, 3);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 3);
}
public double DurationSec => this.Duration * (1D / 32768);
}
}
@@ -0,0 +1,285 @@
namespace OmniPlus.Features
{
using System;
using System.Text;
public class ConfigurationParameters : FeatureRequest
{
const int LENGTH = 62;
public ConfigurationParameters() : base(LENGTH)
{
this.ProgrammableID = new ProgrammableID();
this.FactoryID = new FactoryID();
this.ReadingDigits = new ReadingDigits();
this.Readings = new Readings();
this.OptionalUniDirFields = new OptionalUniDirFields();
this.DeviceID = new DeviceID();
}
public ConfigurationParameters(byte[] response) : base(response, LENGTH)
{
this.ProgrammableID = new ProgrammableID();
this.ProgrammableID.Status = this.Status;
this.ProgrammableID.ToASCIIString(this.bytes, 0, 20);
this.FactoryID = new FactoryID();
this.FactoryID.Status = this.Status;
this.FactoryID.ToASCIIString(this.bytes, 21, 33);
this.ReadingDigits = new ReadingDigits();
this.ReadingDigits.Status = this.Status;
this.ReadingDigits.Count = this.bytes[34];
this.ReadingDigits.Offset = this.bytes[35];
this.Readings = new Readings();
this.Readings.Status = this.Status;
this.Readings.ToASCIIString(this.bytes, 36, 45);
this.OptionalUniDirFields = new OptionalUniDirFields();
this.OptionalUniDirFields.Status = this.Status;
this.OptionalUniDirFields.ToASCIIString(this.bytes, 46, 49);
this.AlarmPersistenceDays = this.bytes[50];
this.DataLogIntervalMins = BitConverter.ToUInt16(this.bytes, 51);
this.DeviceID = new DeviceID();
this.DeviceID.Status = this.Status;
this.DeviceID.ToASCIIString(this.bytes, 53, 61);
}
public ProgrammableID ProgrammableID { get; set; }
public FactoryID FactoryID { get; set; }
public ReadingDigits ReadingDigits { get; set; }
public Readings Readings { get; set; }
public OptionalUniDirFields OptionalUniDirFields { get; set; }
public byte AlarmPersistenceDays { get; set; }
public ushort DataLogIntervalMins { get; set; }
public DeviceID DeviceID { get; set; }
}
public class ConfigurationParametersSet : FeatureRequest
{
const int LENGTH = 80;
public ConfigurationParametersSet() : base(LENGTH)
{
}
private ConfigurationParametersSet(byte[] response) : base(response, LENGTH)
{
}
/// <summary>
/// <para>0 - 20</para>
/// Set Programmable ID request, string is padded and terminated with '\0'
/// +1
/// </summary>
private string programmableID;
public string ProgrammableID
{
get => this.programmableID;
set
{
this.SetASCIIBytes(value, 0, 20);
this.programmableID = this.bytes.ToASCIIString(0, 20);
}
}
/// <summary>
/// <para>21 - 33</para>
/// Set Factory ID request, string padded and terminated with '\0'
/// +1
/// </summary>
private string factoryID;
public string FactoryID
{
get => this.factoryID;
set
{
this.SetASCIIBytes(value, 21, 33);
this.factoryID = this.bytes.ToASCIIString(21, 33);
}
}
/// <summary>
/// <para>34 - 35</para>
/// Set Number of Reading Digits request
/// </summary>
private sbyte nrOfReadingDigits;
public sbyte NumberOfReadingDigits
{
get => this.nrOfReadingDigits;
set
{
BitConverter.GetBytes(value).CopyTo(this.bytes, 34);
this.nrOfReadingDigits = (sbyte)BitConverter.ToInt16(this.bytes, 34);
}
}
/// <summary>
/// <para>36 - 47</para>
/// Set Preset Reading (v1.24), string padded and terminated with '\0'.
/// First Two Characters are set to 0x00 0x00 to indicate that we are programming Totalizer
/// +1
/// </summary>
private string readingPreset;
public string ReadingPreset
{
get => this.readingPreset;
set
{
this.SetASCIIBytes(value, 38, 47);
this.readingPreset = this.bytes.ToASCIIString(38, 47);
}
}
/// <summary>
/// <para>48 - 49</para>
/// Set Optional Uni-directional Fields request
/// </summary>
private ushort optionalFields;
public ushort OptionalUniDirFields
{
get => this.optionalFields;
set
{
BitConverter.GetBytes(value).CopyTo(bytes, 48);
this.optionalFields = BitConverter.ToUInt16(this.bytes, 48);
}
}
/// <summary>
/// <para>50 - 51</para>
/// Set Alarm Persistence Period request. First Byte is always set to 0x00 to indicate Volume Sensor
/// </summary>
public byte AlarmPercistancePeriodDays
{
get => this.bytes[51];
set => this.bytes[51] = value;
}
/// <summary>
/// <para>52 - 54</para>
/// Set Data Log Interval request. First Byte is always set to 0x00 to indicate Volume Sensor
/// </summary>
private ushort dataLogInterval;
public ushort DataLogIntervalMinutes
{
get => this.dataLogInterval;
set
{
BitConverter.GetBytes(value).CopyTo(this.bytes, 53);
this.dataLogInterval = BitConverter.ToUInt16(this.bytes, 53);
}
}
/// <summary>
/// <para>55 - 58</para>
/// Manufacturing Time request
/// </summary>
private uint manifactured;
public uint ManifacturingTime
{
get => this.manifactured;
set
{
BitConverter.GetBytes(value).CopyTo(this.bytes, 55);
this.manifactured = BitConverter.ToUInt16(this.bytes, 55);
}
}
/// <summary>
/// <para>59 - 62</para>
/// System Time request
/// </summary>
private uint timeDrift;
public uint SystemTime
{
get => this.timeDrift;
set
{
BitConverter.GetBytes(value).CopyTo(this.bytes, 59);
this.timeDrift = BitConverter.ToUInt16(this.bytes, 59);
}
}
/// <summary>
/// <para>63</para>
/// Set Reboot Count request
/// </summary>
public byte RebootCount
{
get => this.bytes[63];
set => this.bytes[63] = value;
}
/// <summary>
/// <para>64-79</para>
/// Build Information request, string padded and terminated with '\0'
/// +1
/// </summary>
private string buildInfo;
public string BuildInfo
{
get => this.buildInfo;
set
{
this.SetASCIIBytes(value, 64, 79);
this.buildInfo = this.bytes.ToASCIIString(64, 79);
}
}
/// <summary>
/// <para>80-89</para>
/// Set Device ID String, string is padded and terminated with '\0'
/// +1
/// </summary>
private string deviceID;
public string DeviceID
{
get => this.deviceID;
set
{
this.SetASCIIBytes(value, 80, 89);
this.deviceID = this.bytes.ToASCIIString(80, 89);
}
}
private void SetASCIIBytes(string value, int start, int end)
{
if (string.IsNullOrWhiteSpace(value))
{
return;
}
value = value.Trim('\0');
var asciiBytes = Encoding.ASCII.GetBytes(value);
var asciiLength = asciiBytes.Length;
var asciiIndex = 0;
while (start >= 0 && start <= end && asciiIndex < asciiLength)
{
this.bytes[start++] = asciiBytes[asciiIndex++];
}
}
}
}
@@ -0,0 +1,24 @@
namespace OmniPlus.Features
{
/// <summary>
/// All printable characters except ';' (semicolon) and ',' (comma) are allowed.
/// </summary>
public class CustomerText : ASCIIString
{
const int LENGTH = 20;
public CustomerText() : base(LENGTH)
{
}
public CustomerText(byte[] response) : base(response, LENGTH)
{
}
public CustomerText(string value) : base(value, LENGTH)
{
}
}
}
@@ -0,0 +1,20 @@
namespace OmniPlus.Features
{
public class DeviceID : ASCIIString
{
const int LENGTH = 10;
public DeviceID() : base(LENGTH)
{
}
public DeviceID(byte[] response) : base(response, LENGTH)
{
}
public DeviceID(string value) : base(value, LENGTH)
{
}
}
}
@@ -0,0 +1,17 @@
namespace OmniPlus.Features.Enums
{
public enum MessurementUnits : byte
{
CubicMeters = 0,
CubicFeet = 1,
CubicInches = 2,
CubicYards = 3,
USGallons = 4,
ImperialGallons = 5,
AcreFeet = 6,
Kiloliters = 7,
Liters = 8,
WattHours = 9,
KilowattHours = 10,
}
}
@@ -0,0 +1,16 @@
namespace OmniPlus.Features.Enums
{
public enum ReadingSettings : byte
{
/// <summary>
/// When forward and reverse volumes are supported,
/// this will be equal to the value of the expression (total forward volume) (total reverse volume).
/// Use this value for sensors with no concept of forward or reverse.
/// </summary>
Totalizer = 0x00,
TotalForward = 0x01,
TotalReverse = 0x02,
LifetimeTotalizer = 0x03,
TestTotalizer = 0x04,
}
}
@@ -0,0 +1,52 @@
namespace OmniPlus.Features.Enums
{
public enum Status
{
/// <summary>
/// Used by communication devices to indicate communication failure/timeout.
/// Should not be used by a slave device implementing UI-1236.
/// </summary>
FailureOrTimeout = 0x00,
/// <summary>
/// Command complete, no errors
/// </summary>
Completed = 0x01,
/// <summary>
/// Error, unable to execute command
/// </summary>
UnableToExecute = 0x02,
/// <summary>
/// Error, unknown command
/// </summary>
UnknownCommand = 0x03,
/// <summary>
/// Error, unsupported control bit pattern
/// </summary>
UnsupportedControl = 0x04,
/// <summary>
/// Error, command blocked by factory seal.
/// Added in version B1.23
/// </summary>
BlockedBySeal = 0x05,
/// <summary>
/// Custom field.
/// </summary>
Request = 0x80,
/// <summary>
/// Frame received, no error
/// </summary>
FrameReceived = 0xFC,
/// <summary>
/// Message corrupt
/// </summary>
MessageCorrupt = 0,
/// <summary>
/// Wait status
/// </summary>
Waiting = 0xFE,
/// <summary>
/// Used by communication devices to indicate unrecognized communication device command.
/// </summary>
UnrecognizedDevice = 0xFF
}
}
@@ -0,0 +1,12 @@
namespace OmniPlus.Features.Enums
{
public enum TimeUnits : byte
{
Milliseconds = 0,
Seconds = 1,
Minutes = 2,
Hours = 3,
Days = 4,
Years = 5,
}
}
@@ -0,0 +1,33 @@
namespace OmniPlus.Features
{
using System;
public class Epoch20000101 : FeatureRequest
{
static readonly DateTime epoch = new DateTime(2000, 01, 01, 00, 00, 00, DateTimeKind.Utc);
const int LENGTH = 4;
public Epoch20000101() : base(LENGTH)
{
}
public Epoch20000101(byte[] response) : base(response, LENGTH)
{
}
public uint SecondsSince
{
get => BitConverter.ToUInt32(this.bytes, 0);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 0);
}
public DateTime DateTime
{
get => epoch.AddSeconds(this.SecondsSince);
set => this.SecondsSince = (uint)(value - epoch).TotalSeconds;
}
public static uint UTCNow => new Epoch20000101 { DateTime = DateTime.UtcNow }.SecondsSince + 10;
}
}
@@ -0,0 +1,24 @@
namespace OmniPlus.Features
{
public class FactoryID : ASCIIString
{
const int LENGTH = 13;
public FactoryID() : base(LENGTH)
{
}
public FactoryID(byte[] response) : base(response, LENGTH)
{
}
public FactoryID(string value) : base(value, LENGTH)
{
}
public static implicit operator FactoryID(string value)
=> new FactoryID { Value = value };
}
}
@@ -0,0 +1,21 @@
namespace OmniPlus.Features
{
public class FactorySeal : FeatureRequest
{
const int LENGTH = 1;
public FactorySeal() : base(LENGTH)
{
}
public FactorySeal(byte[] response) : base(response, LENGTH)
{
}
public bool Sealed
{
get => this.bytes[0] == 1;
set => this.bytes[0] = (byte)(value ? 1 : 0);
}
}
}
@@ -0,0 +1,32 @@
namespace OmniPlus.Features
{
using System;
public class FeatureRequest : FeatureResponse
{
public FeatureRequest(int length)
: base(length)
=> this.length = length;
public FeatureRequest(byte[] response, int length = 0)
: base(response, length)
=> this.length = length;
public byte[] this[params byte[] cmd]
{
get
{
var cmdLength = cmd.Length;
var request = new byte[this.length + cmdLength];
cmd.CopyTo(request, 0);
this.bytes.CopyTo(request, cmdLength);
return request;
}
}
internal void CopyTo(byte[] bytes, int start)
=> Array.Copy(this.bytes, 0, bytes, start, this.length);
}
}
@@ -0,0 +1,52 @@
namespace OmniPlus.Features
{
using OmniPlus.Features.Enums;
using System;
public class FeatureResponse
{
protected int length;
protected readonly byte[] bytes;
public FeatureResponse(int length = 0)
{
this.length = length;
this.bytes = new byte[length];
}
public FeatureResponse(byte[] response, int length = 0) : this(length)
{
if (response != null)
{
var responseLength = response.Length;
if (responseLength > 0)
{
this.Status = (Status)response[0];
}
if (responseLength > 1)
{
for (int src = 1, dst = 0; src < responseLength && dst < this.length; src++, dst++)
{
this.bytes[dst] = response[src];
}
}
}
}
public Status Status { get; set; }
public bool Completed => this.Status == Status.Completed;
public override bool Equals(object obj)
=> obj is FeatureResponse outer && outer.bytes == this.bytes;
public override int GetHashCode()
=> this.bytes.GetHashCode();
public override string ToString()
=> BitConverter.ToString(this.bytes);
}
}
@@ -0,0 +1,372 @@
namespace OmniPlus.Features
{
public class Features
{
/// <summary>
/// The View Factory ID command shall cause the slave device to transmit the factory ID.
/// The CDU shall consist of the command byte.
/// The slave device shall respond by sending a message containing a status byte followed by the ASCII ID string
/// terminated by a NULL character.
/// <para>Note: This value is reported in the ;K field of UI-1203s AMR string.</para>
/// </summary>
public const byte VIEW_FACTORY_ID = 0x01;
/// <summary>
/// The Set Factory ID command shall set the device ID.
/// This command shall only be executed at the factory.
/// The CDU shall consist of the one-byte command field followed by one to twelve ASCII alphanumeric characters.
/// The ID shall be NULL terminated.
/// The length of the ID string is device dependent.
/// <para>It is recommended that all devices implement this command, though it may be protected by a factory seal.</para>
/// </summary>
public const byte SET_FACTORY_ID = 0x02;
/// <summary>
/// The View Programmable ID command shall cause the slave device to return the customer ID.
/// The CDU shall consist of the command byte.
/// The slave device shall transmit a message block containing a NULL terminated ASCII string
/// representing the customer ID.
/// If the ID is NULL, a single NULL character (hex 00) shall be returned in the response string.
/// <para>Note: This is the ID that is always reported in the UI-1203 AMR string.</para>
/// </summary>
public const byte VIEW_PROGRAMMABLE_ID = 0x03;
/// <summary>
/// The Set Programmable ID command shall set the customer ID in the slave device.
/// The CDU shall consist of the one byte command code followed by a NULL terminated ASCII string
/// of 1-20 alphanumeric characters.
/// The ID shall be cleared and set to NULL if this command is sent with a string consisting
/// of a single NULL (hex 00) character.
/// <para>
/// Note: This sets the ID that is required to be reported in the UI-1203 AMR string.
/// In Fixed Length reading mode, the length is restricted to 8 characters.
/// In Variable Length reading mode, the ;I field is limited to 12 characters.
/// Some devices my reject long IDs based on the UI-1203 restrictions.
/// </para>
/// <para>It is recommended that all devices implement this command.</para>
/// </summary>
public const byte SET_PROGRAMMABLE_ID = 0x04;
/// <summary>
/// The View Version and Type command is used to determine the type of device being programmed.
/// The CDU shall consist of the command byte.
/// The slave device shall respond by sending data containing the protocol version, device type and software version.
/// The format of the data is three comma-delimited strings with a single NULL terminator.
/// [Protocol version],[Device type],[Software version]
/// Each string consists of a maximum of eight characters.
/// </summary>
public const byte VIEW_VERSION_AND_TYPE = 0x05;
/// <summary>
/// The View Customer Text command shall cause the slave device to return a string containing the customer text field.
/// The CDU shall consist of the command byte.
/// The slave device shall transmit a message block containing a NULL terminated ASCII string
/// representing the customer text field.
/// If the ID is NULL, a single NULL character (hex 00) shall be returned in the response string.
/// <para>Note: This is the value reported in the ;J field of the UI-1203 AMR string.</para>
/// </summary>
public const byte VIEW_CUSTOMER_TEXT = 0x07;
/// <summary>
/// The Set Customer Text command shall set the Customer Text field in the slave device.
/// The CDU shall consist of the one byte command code followed by a NULL terminated ASCII string
/// of 1-20 alphanumeric characters.
/// The Customer Text field shall be cleared and set to NULL if this command is sent with a string consisting
/// of a single NULL (hex 00) character.
/// <para>Note: This is the value reported in the ;J field of the UI-1203 AMR string.</para>
/// </summary>
public const byte SET_CUSTOMER_TEXT = 0x08;
/// <summary>
/// The View Reading Digits command shall cause the slave device to return the number of reading digits.
/// The slave device shall transmit a message block containing two 8-bit binary numbers:
/// <para>
/// 0: The first number represents the number of reading digits to report in the AMR string, from 4 to 9.
/// If 9, then the; NB field will be enabled in the AMR string.
/// </para>
/// <para>
/// 1: The second number represents the AMR Reading Offset,
/// which indicates the offset into the totalizer value where the AMR reading begins,
/// counting from the right.The value is either 0 or negative.A value of 0 means to discard no digits.
/// A value of -1 means to discard the least significant digit, etc.
/// </para>
/// <para>
/// For example, if the totalizer on the meter shows 876543210,
/// and the number of reading digits is 5 with an AMR Reading Offset of -2 (0xFE),
/// the AMR reading reported will be 65432.
/// </para>
/// <para>
/// Note that previously, the AMR Reading Offset was defined to be the number of digits to the right of the decimal point
/// being reported, but no known devices implemented this command that way,
/// since the position of the decimal point was unknown (electronically) on mechanical registers.
/// </para>
/// </summary>
public const byte VIEW_READING_DIGITS = 0x09;
/// <summary>
/// The Set Number of Reading Digits command shall set the number of reading digits reported in the AMR string.
/// The CDU shall consist of the one-byte command code followed by two 8-bit binary numbers.
/// The first octet represents the total number of digits in the reading string.
/// The second octet represents the AMR Reading Offset (see cmd 0x09).
/// </summary>
public const byte SET_READING_DIGITS = 0x0A;
/// <summary>
/// The View Reading Units command shall cause the slave device to return the reading units.
/// The CDU shall consist of the command byte.
/// The slave device shall transmit an eight bit binary number representing the reading units.
/// The table listing reading units and the associated number is contained in UI-1203.
/// On devices that do not know their reading units, the value 255 (0xFF) will be returned.
/// </summary>
public const byte VIEW_READING_UNITS = 0x0B;
/// <summary>
/// The Set Reading Units command shall set the reading units for the slave device.
/// The CDU shall consist of the one-byte command code followed by an eight bit binary number representing the reading units.
/// The table listing the reading units and the associated number is contained in UI-1203.
/// On some devices, sending the value 255 (0xFF) will disable the units subfield of the UI-1203 ; R field,
/// on others the resolution and units subfields will be disabled.On some devices,
/// sending the value 255 (0xFF) will result in an Unable to Execute response.
/// On many devices, there is no error checking on the value, and it is possible to set the value to something invalid.
/// </summary>
public const byte SET_READING_UNITS = 0x0C;
/// <summary>
/// The View Rate Units command shall cause the slave device to return the rate units.
/// The CDU shall consist of the command byte.
/// The slave device shall transmit two bytes representing the rate units.
/// The first byte represents the totalization units and the second byte represents the time units.
/// The table listing the rate units and the associated numbers is contained in UI-1203.
/// </summary>
public const byte VIEW_RATE_UNITS = 0x0D;
/// <summary>
/// The Set Rate Units command shall set the rate units for the slave device.
/// The CDU shall consist of the one byte command code followed by two eight bit binary numbers
/// representing the rate units.
/// The first byte represents the volume units and the second byte represents the time units.
/// The table listing the rate units and the associated numbers is contained in UI-1203.
/// </summary>
public const byte SET_RATE_UNITS = 0x0E;
/// <summary>
/// The View Reading Resolution command shall cause the slave device to return the resolution setting for the reading.
/// The CDU shall consist of the command byte.
/// The slave device shall respond by sending a signed eight bit binary number representing
/// the reading resolution in powers of ten.
/// The value returned is the resolution reported in the UI-1203 read responses ;R field,
/// if the resolution subfield is enabled.
/// On some devices, if the resolution subfield is disabled in the UI-1203 read response,
/// this command will return -128 (0x80).
/// On other devices, the resolution of the currently selected AMR digits is returned.
/// </summary>
public const byte VIEW_READING_RESOLUTION = 0x0F;
/// <summary>
/// The Set Reading Resolution command shall set the slave device resolution for the reading.
/// The CDU consists of the command byte followed by a signed eight bit binary number representing
/// the reading resolution in powers of ten.
/// The maximum range of reading resolution is specified in UI-1203.
/// Use this command to enable the resolution subfield of the UI-1203 ; R field.
/// The value -128 (0x80) disables that subfield on most devices.On many devices,
/// there is no error checking on this value, and what is set is what will be reported in the ; R field,
/// even if it is incorrect.
/// If your goal is to change the resolution of the reported reading,
/// cmd 0x0A Set Number of Reading Digits is most likely the command you need.
/// </summary>
public const byte SET_READING_RESOLUTION = 0x10;
/// <summary>
/// The View Rate Resolution command shall cause the slave device to return the resolution setting for the rate.
/// The CDU shall consist of the command byte.
/// The slave device will send a response message with a signed eight bit binary number representing
/// the rate resolution in powers of ten.
/// </summary>
public const byte VIEW_RATE_RESOLUTION = 0x11;
/// <summary>
/// The Set Rate Resolution command shall set the slave device resolution for rate.
/// The CDU consists of the command code followed by a signed eight bit binary number representing
/// the rate resolution in powers of ten.
/// The maximum range of rate resolution is specified in UI-1203.
/// </summary>
public const byte SET_RATE_RESOLUTION = 0x12;
/// <summary>
/// As of B1.23, there are two variants of this command:
/// If the CDU consists of only the command byte.
/// The slave device shall return a message block containing a NULL terminated ASCII string of one to eight characters.
/// This version of the command existed in B1.22.
/// In B1.23, the command was updated to allow for more than 8 digits and to support multiple sensors.
/// The format of the B1.23 version of the command is shown in the table below.The response will be a
/// null-terminated ASCII string.
/// </summary>
public const byte VIEW_READINGS = 0x13;
/// <summary>
/// As of B1.23, there are two variants of this command:
/// If the CDU consists of only the command byte.
/// The slave device shall return a message block containing a NULL terminated ASCII string of one to eight characters.
/// This version of the command existed in B1.22.
/// In B1.23, the command was updated to allow for more than 8 digits and to support multiple sensors.
/// The format of the B1.23 version of the command is shown in the table below.The response will be a
/// null-terminated ASCII string.
/// </summary>
public const byte SET_READING_PRESET = 0x14;
/// <summary>
/// The View Reading Mode command shall cause the slave device to return the current value of the reading mode.
/// The CDU shall consist of the command byte. The slave device shall return a message block
/// containing one byte binary number representing the reading mode.
/// If the reading mode is not one of the formats specified in the description of cmd 0x16,
/// the response for this command will be 0xFF to indicate Undefined.
/// Command 0x27 which was introduced with B1.23 is preferable to this command as it is more flexible.
/// </summary>
public const byte VIEW_READING_MODE = 0x15;
/// <summary>
/// The Set Reading Mode command shall set the unidirectional reading mode in a register.
/// The CDU shall consist of the command byte followed by a one byte binary number.
/// The number represents the unidirectional reading mode setting as shown below in table three.
/// Unidirectional reading modes and their respective fields are described
/// in the communication protocol document(s) for each device.
/// Some devices use different definitions than those found in the table above.
/// Most device report the; R field before the; I field.
/// Command 0x28 which was introduced with B1.23 is preferable to this command as it is more flexible.
/// </summary>
public const byte SET_READING_MODE = 0x16;
/// <summary>
/// The View Build Information command shall cause the slave device to return a string containing the build information.
/// The CDU shall consist of the command byte.
/// The slave device shall transmit a message block containing a NULL terminated ASCII string
/// representing the build information.
/// If the ID is NULL, a single NULL character (hex 00) shall be returned in the response string.
/// </summary>
public const byte VIEW_BUILD_INFORMATION = 0x17;
/// <summary>
/// The Set Build Information command shall set the build Information field in the slave device.
/// The CDU shall consist of the one byte command code followed by a NULL terminated ASCII string
/// of 1-14 alphanumeric characters.
/// The Build Info field shall be cleared and set to NULL if this command is sent with a string consisting of
/// a single NULL (hex 00) character.
/// Build information may vary from product to product.
/// Build information may include, but not be limited to, date, time, manufacturing facility code,
/// production line code, etc.
/// Each project should detail build information data in its respective communication protocol specification document.
/// </summary>
public const byte SET_BUILD_INFORMATION = 0x18;
public const byte VIEW_ALARM_SETTINGS = 0x1F;
public const byte SET_ALARM_SETTINGS = 0x20;
public const byte VIEW_ALARMS_STATE = 0x21;
public const byte CLEAR_ALARMS = 0x22;
public const byte DEVICE_SPECIFIC = 0xFD;
/// <summary>
/// Command is provided to allow the Factory to view multiple System Configurations with one
/// UI1236 command to save time during Factory Configuration.
/// </summary>
public const byte VIEW_SYSTEM_PARAMETERS = 0xC6;
/// <summary>
/// Command is provided to allow the Factory to view multiple Configurations with
/// one UI1236 command to save time during Factory Configuration.
/// Command is configured to take 0 to 1 parameters.
/// To keep the command backward compatible with previous versions of the command,
/// if no parameters are provided, the command will generate a response
/// with all of the response elements up to View Device ID String but no including the View ID String.
/// </summary>
public const byte VIEW_CONFIGURATION_PARAMETERS = 0xC7;
public const byte SET_CONFIGURATION_PARAMETERS = 0xC8;
/// <summary>
/// View volume per pulse.
/// Volume per pulse is the amount of volume (in units of milliliters) that is added to the volume counter
/// when one pulse of a meter shaft magnet is detected.
/// (Commonly meter shaft magnets have two or four magnetic poles and produce four or eight pulses per full rotation.)
/// </summary>
public const byte VIEW_INPUT_VOLUME = 0x02;
/// <summary>
/// Set volume per pulse.
/// </summary>
public const byte SET_INPUT_VOLUME = 0x03;
/// <summary>
/// Command is used to test the accuracy of meter and to calibrate the Meter Register assembly.
/// This is a factory command and is only available when the Register is not Factory Sealed.
/// The time to execute the command is determined by the present flow on the meter when
/// the command was sent and how many rotations are requested to be collected.
/// Since the time is not known by the Register, it is up to the user to provide a maximum time the command will execute.
/// If the test does not complete by the maximum time, a failure response will be generated when the Test Results are requested.
/// Once the command is sent to execute the calibration procedure,
/// the user will receive a response indicating that the test has started and then the Register will perform the test.
/// While the test is being performed, the Register will be unresponsive until the test has completed.
/// The user must wait the appropriate time to before requesting the results.
/// Based on the flow rate and the number of samples it takes to complete the test,
/// the user should be able to calculate how long to wait before requesting results.
/// </summary>
public const byte CHAMBER_CALIBRATION = 0x67;
/// <summary>
/// System time (a.k.a. epoch time) is the number of seconds from midnight January 1, 2000 UTC.
/// </summary>
public const byte VIEW_SYSTEM_TIME = 0x10;
/// <summary>
/// After powering up system time starts at midnight January 2, 2000 UTC/GMT; i.e. 86400 seconds from January 1, 2000 epoch.
/// System time can be advanced forward, but cannot be changed into the past.
/// Setting system time to 0 while the register is not sealed causes the following to happen:
/// <para>• Volume data log is cleared</para>
/// <para>• Epoch time and volume reading are cleared</para>
/// <para>• Periodic alarm log is cleared</para>
/// <para>• Alarm counters are cleared</para>
/// <para>• Processor is reset(command times out).</para>
/// <para>• Upon reset system time is 86400 seconds(24 hours, January 2, 2000)</para>
/// When system time is successfully changed by this command (except when it is set to 0),
/// a new boot recovery record is written into flash.This way time,
/// current volume reading and alarm counts can be recovered if Set System Time is followed by a reboot.
/// </summary>
public const byte SET_SYSTEM_TIME = 0x11;
/// <summary>
/// Get manufacturing date and time which is programmed into the register at time of manufacture.
/// </summary>
public const byte VIEW_MANIFACTURING_TIME = 0x39;
/// <summary>
/// Set manufacturing date and time.
/// If manufacturing date/time specified in the command payload is newer than the system time of the register,
/// the register will update system time to the time specified in this command in addition to setting manufacturing time.
/// </summary>
public const byte SET_MANIFACTURING_TIME = 0x3A;
/// <summary>
/// The command is used to view the Register Configuration of the Meter
/// </summary>
public const byte VIEW_REGISTER_SETTINGS = 0x24;
/// <summary>
/// Command is used to modify majority of the Factory Settings at one time to speed up Factory initialization time.
/// </summary>
public const byte SET_REGISTER_SETTINGS = 0x25;
/// <summary>
/// Command is used to program the Device ID String that is returned in the UI1236 05 Command to View Version and Type command.
/// The command is only allowed when the Register has not been factory sealed.
/// </summary>
public const byte SET_DEVICE_ID = 0x27;
/// <summary>
/// <para>0x00 means factory seal has not been set.</para>
/// <para>0x01 means factory seal has been set.</para>
/// </summary>
public const byte VIEW_FACTORY_SEAL = 0x63;
public const byte SET_FACTORY_SEAL = 0x64;
/// <summary>
/// Command is a Generic command used by the Factory to test,
/// calibrate or configure portions of the system that are not part of the normal operation of the meter.
/// <para>01 - Verify NFC Connectivity</para>
/// <para>02 - Enable NFC Periodic Updates and Initialize NFC Storage Memory</para>
/// <para>03 - Disable NFC Periodic Updates</para>
/// <para>04 - Force Update NFC NDEF data</para>
/// <para>05 - Force Update NFC Periodic RMA data</para>
/// <para>06 - View Sensor Setting</para>
/// <para>07 - Set Sensor Settings</para>
/// <para>0A - Board Variant and PcbId</para>
/// <para>0B - NFC Status</para>
/// </summary>
public const byte METROLOGY_TEST = 0x65;
}
}
@@ -0,0 +1,119 @@
namespace OmniPlus.Features
{
using System;
public static class FeaturesExtensions
{
public const int BYTE_BITS = 8;
private static readonly byte[] EmptyArray = new byte[0];
public static byte[] GetBits(this byte value)
{
var bits = new byte[BYTE_BITS];
for (byte i = 0; i < BYTE_BITS; i++)
{
bits[i] = (byte)(value >> i & 1);
}
return bits;
}
public static byte[] GetBits(this byte[] bytes)
{
var bytesL = bytes.Length;
var bitsL = bytesL * BYTE_BITS;
var bits = new byte[bitsL];
for (int i = 0; i < bytesL; i++)
{
for (int b = 0; b < BYTE_BITS; b++)
{
bits[i + b] = (byte)(bytes[i] >> b & 1);
}
}
return bits;
}
public static byte GetUint8(this byte x, int start, int length)
{
var src = x.GetBits();
var dst = new byte[8];
Array.Copy(src, start, dst, 0, length);
return dst.ToUint8();
}
public static byte[] Reverse(this byte[] bytes)
{
if (bytes is null || bytes.Length <= 1)
{
return bytes;
}
var length = bytes.Length;
var _length = length / 2;
var last = length - 1;
for (int i = 0; i < _length; i++)
{
var current = bytes[i];
bytes[i] = bytes[last - i];
bytes[last - i] = current;
}
return bytes;
}
public static void SetUint8(this ref byte x, int start, int length, byte value)
{
var src = value.GetBits();
var dst = x.GetBits();
Array.Copy(src, 0, dst, start, length);
x = dst.ToUint8();
}
public static byte[] Subarray(this byte[] bytes, int start, int length)
{
var subarray = EmptyArray;
if (bytes?.Length >= start + length)
{
subarray = new byte[length];
Buffer.BlockCopy(bytes, start, subarray, 0, length);
}
return subarray;
}
public static string ToASCIIString(this byte[] bytes, int start, int end)
{
var asciiString = string.Empty;
while (start >= 0 && end < bytes.Length && start < end)
{
asciiString += (char)bytes[start++];
}
return asciiString;
}
public static byte ToUint8(this byte[] bits)
{
var sum = default(byte);
for (byte i = 0; i < bits.Length; i++)
{
sum ^= (byte)(bits[i] << i);
}
return sum;
}
}
}
@@ -0,0 +1,49 @@
namespace OmniPlus.Features
{
using System;
public class InputVolume : FeatureRequest
{
const int LENGTH = 6;
public InputVolume() : base(LENGTH)
{
}
public InputVolume(byte[] response) : base(response, LENGTH)
{
}
public byte Direction
{
get => this.bytes[0];
set => this.bytes[0] = value;
}
public byte IntPart
{
get => this.bytes[1];
set => this.bytes[1] = value;
}
public ushort Fraction
{
get => BitConverter.ToUInt16(this.bytes, 2);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 2);
}
public byte Size
{
get => this.bytes[4];
set => this.bytes[4] = value;
}
public byte Range
{
get => this.bytes[5];
set => this.bytes[5] = value;
}
public ushort IntPartFull => BitConverter.ToUInt16(this.bytes, 0);
}
}
@@ -0,0 +1,13 @@
namespace OmniPlus.Features
{
using System;
public class ManifacturingTime : Epoch20000101
{
public static implicit operator ManifacturingTime(DateTime dateTime)
=> new ManifacturingTime
{
DateTime = dateTime,
};
}
}
@@ -0,0 +1,28 @@
namespace OmniPlus.Features
{
using System;
/// <summary>
/// TODO: Need more investigation of the purpose
/// </summary>
public class OptionalUniDirFields : ASCIIString
{
const int LENGTH = 4;
public OptionalUniDirFields() : base(LENGTH)
{
}
public OptionalUniDirFields(byte[] response) : base(response, LENGTH)
{
}
public OptionalUniDirFields(string value) : base(value, LENGTH)
{
}
public static implicit operator ushort(OptionalUniDirFields obj)
=> BitConverter.ToUInt16(obj.bytes, 0);
}
}
@@ -0,0 +1,26 @@
namespace OmniPlus.Features
{
using System;
public class ProgrammableID : ASCIIString
{
const int LENGTH = 20;
public ProgrammableID() : base(LENGTH)
{
}
public ProgrammableID(byte[] response) : base(response, LENGTH)
{
}
public ProgrammableID(string value) : base(value, LENGTH)
{
}
public static implicit operator ProgrammableID(string value)
=> new ProgrammableID { Value = value };
}
}
@@ -0,0 +1,47 @@
namespace OmniPlus.Features
{
using System;
/// <summary>
/// Rate resolution depends on the reading units and the size of the meter.
/// The customer is allowed to change the units of measure but they are not allowed to change Meter Range
/// which indicates the actual size of the meter.
/// </summary>
public class RateResolution : FeatureRequest
{
const int LENGTH = 2;
public RateResolution() : base(LENGTH)
{
}
public RateResolution(byte[] response) : base(response, LENGTH)
{
}
public sbyte Value
{
get => (sbyte)BitConverter.ToUInt16(this.bytes, 0);
set => BitConverter
.GetBytes(value)
.CopyTo(this.bytes, 0);
}
}
}
/*
* TODO: Implement the rate resolution table below:
* ------------------------------------------------------------------
* Meter Range Cubic Meters Cubic Feet Gallons Acre Feet
* ------------------------------------------------------------------
* m³/h cf/min gal/min
* igal/min
* ------------------------------------------------------------------
* 1 ½” or 2” -3 -3 -3 Not Supported
* 3” or 4” Extended -3 -3 -3 Not Supported
* 3” or 4” Normal -3 -3 -3 Not Supported
* 6” -3 -2 -2 Not Supported
* 8” -2 -2 -2 Not Supported
* 10” -2 -2 -2 Not Supported
*/
@@ -0,0 +1,52 @@
namespace OmniPlus.Features
{
using OmniPlus.Features.Enums;
/// <summary>
/// Omni+ flow rate units are independent of the reading units.
/// <para>Note: Acre Feet per Hour is not supported.</para>
/// </summary>
public class RateUnits : FeatureRequest
{
const int LENGTH = 2;
public RateUnits() : base(LENGTH)
{
}
public RateUnits(byte[] response) : base(response, LENGTH)
{
}
public MessurementUnits Flow
{
get => (MessurementUnits)this.bytes[0];
set
{
var flow = (byte)MessurementUnits.CubicMeters;
var time = (byte)TimeUnits.Hours;
switch (value)
{
case MessurementUnits.CubicFeet:
flow = (byte)value;
time = (byte)TimeUnits.Minutes;
break;
case MessurementUnits.USGallons:
flow = (byte)value;
time = (byte)TimeUnits.Minutes;
break;
case MessurementUnits.ImperialGallons:
flow = (byte)value;
time = (byte)TimeUnits.Minutes;
break;
}
this.bytes[0] = flow;
this.bytes[1] = time;
}
}
public TimeUnits Time => (TimeUnits)this.bytes[1];
}
}
@@ -0,0 +1,43 @@
namespace OmniPlus.Features
{
using System;
public class ReadingDigits : FeatureRequest
{
const int LENGTH = 2;
public ReadingDigits() : base(LENGTH)
{
}
public ReadingDigits(byte[] response) : base(response, LENGTH)
{
}
public byte Count
{
get => this.bytes[0];
set => this.bytes[0] = value;
}
public byte Offset
{
get => this.bytes[1];
set => this.bytes[1] = value;
}
public static implicit operator ReadingDigits(sbyte value)
{
var bytes = BitConverter.GetBytes(value);
return new ReadingDigits
{
Count = bytes[0],
Offset = bytes[1]
};
}
public static implicit operator sbyte(ReadingDigits readingDigits)
=> (sbyte)BitConverter.ToInt16(new[] { readingDigits?.Count ?? 0, readingDigits?.Offset ?? 0 }, 0);
}
}
@@ -0,0 +1,28 @@
namespace OmniPlus.Features
{
/// <summary>
/// Response will either indicate Fixed or Undefined (like ally). Use cmd 0x27 instead.
/// Fixed mode requires a Programmable ID of exactly 8 characters and exactly 4 AMR digits.
/// If Programmable ID or number of AMR digits is invalid, command will return Unable to Execute.
/// The following actions will cause the register to exit Fixed mode:
/// Setting the reading string fields with cmd 0x28 will exit fixed mode.
/// Changing the Programmable ID to a length other than exactly 8 characters will exit fixed mode.
/// Changing the number AMR digits to a value other than 4 will exit fixed mode.
/// If programmable ID or number of AMR digits is set to something invalid for fixed mode,
/// then to re - enter fixed mode requires correcting the changed parameter and sending command 0x16 Set Reading Mode again.
/// </summary>
public class ReadingMode : FeatureRequest
{
const int LENGTH = 13;
public ReadingMode() : base(LENGTH)
{
}
public ReadingMode(byte[] response) : base(response, LENGTH)
{
}
// TODO: To be implemented.
}
}
@@ -0,0 +1,44 @@
namespace OmniPlus.Features
{
using OmniPlus.Features.Enums;
using System.Text;
/// <summary>
/// Versions B1.24 of this command are supported. Total Forward and Total Reverse are not supported.
/// Absence of command payload(i.e.of the reading preset) clears the Totalizer reading unless
/// Display View is set to Totalizer Test View which sets the Test Totalizer Counter to 0.
/// Command will support setting Totalizer Value, Test Totalizer Value and the Lifetime Totalizer value
/// while the device is not factory sealed.
/// If the device is factory sealed, the Lifetime Totalizer is prevented from being changed
/// and Test Totalizer is limited to setting it to 0.
/// The Set Reading Preset command shall send the value to be used as the initial reading.
/// The CDU consists of a one-byte command code followed by a NULL terminated ASCII string of one to eight characters
/// representing the preset reading value.This value is assumed to be in the current units used for totalization.
/// In protocol version B1.23, 9 digits are allowed on devices that support it.
/// Some devices that implement B1.22 may also support a 9-digit null-terminated string.
/// </summary>
public class ReadingPreset : FeatureRequest
{
const int LENGTH = 11;
public ReadingPreset() : base(LENGTH)
{
for (int i = 2; i < 11; i++)
{
this.bytes[i] = (byte)'0';
}
}
public byte SensorID
{
get => this.bytes[0];
set => this.bytes[0] = value;
}
public ReadingSettings Setting
{
get => (ReadingSettings)this.bytes[1];
set => this.bytes[1] = (byte)value;
}
}
}
@@ -0,0 +1,42 @@
namespace OmniPlus.Features
{
using System;
/// <summary>
/// Reading Resolution of the device depends on reading units and the size of the Meter.
/// The customer is allowed to change the Units of measure but they are not able to change
/// the Reading Resolution for the Meter Range.
/// </summary>
public class ReadingResolution : FeatureRequest
{
const int LENGTH = 2;
public ReadingResolution() : base(LENGTH)
{
}
public ReadingResolution(byte[] response) : base(response, LENGTH)
{
}
public sbyte Value
{
get => (sbyte)BitConverter.ToUInt16(this.bytes, 0);
set => BitConverter
.GetBytes(value)
.CopyTo(this.bytes, 0);
}
}
}
/*
* TODO: Implement the reading resolution table below:
* -----------------------------------------------------------------------------------------------
* Meter Range Cubic Meters Cubic Feet Imperial Gallons Gallons Acre Feet
* -----------------------------------------------------------------------------------------------
* 1 ½” or 2” -3 -2 0 0 -5
* 3” or 4” Extended -2 -2 0 0 -5
* 3” or 4” Normal -2 0 0 0 -5
* 6” -2 0 0 0 -5
* 8” -2 0 0 0 -4
*/
@@ -0,0 +1,31 @@
namespace OmniPlus.Features
{
using OmniPlus.Features.Enums;
/// <summary>
/// 0xFF in the reading units byte does not change the reading units.
/// 0xFF disables reporting of multiplier and units in the reading and flowrate uni-directional fields.
/// Setting reading units to one of the actual supported values,
/// enables reporting of multiplier and units in the reading and flowrate uni-directional fields.
/// Reading Resolution is based on Meter Range and Units of Measure.
/// Omni+ does not support a separate command to set reading resolution.
/// </summary>
public class ReadingUnits : FeatureRequest
{
const int LENGTH = 1;
public ReadingUnits() : base(LENGTH)
{
}
public ReadingUnits(byte[] response) : base(response, LENGTH)
{
}
public MessurementUnits Value
{
get => (MessurementUnits)this.bytes[0];
set => this.bytes[0] = (byte)value;
}
}
}
@@ -0,0 +1,58 @@
namespace OmniPlus.Features
{
using OmniPlus.Features.Enums;
/// <summary>
/// Versions B1.24 of this command are supported. Total Forward and Total Reverse are not supported.
/// <para>
/// If sensor filed is set to 0, command supports viewing Lifetime Totalizer Value(Setting of 3)
/// and Test Totalizer Value(Setting of 4). If reading the Life Time totalizer value,
/// the number of digits reported will be increased to 13 digits to support a larger Reading.
/// </para>
/// <para>
/// Requesting a reading from an invalid sensor ID or reading type will result in an “Unable to execute” response.
/// </para>
/// <para>
/// Omni supports the B1.24 version of the command which allows additional functionality
/// if more data is supplied in the payload. If 2 or more bytes of the payload are provided,
/// the first byte is used to indicate the sensor with 0 being a volume sensor.
/// The second byte of the payload is which one of the specified type of sensor is being read.
/// If a third byte of the payload is provided, the command will also provide the multiplier resolution of the sensor reading.
/// Omni only supports the Volume Sensor.
/// </para>
/// <para>
/// Note: Because of the size of the Meter,
/// the Life Time Totalizer may exceed the reportable range using the Resolution set for the Totalizer value.
/// When the Life Time Totalizer value exceeds 12 reportable digits and the Resolution is not 0,
/// the Resolution will be reduced until either the whole part of the Life Time Totalizer is reported
/// or until there are no more Resolution steps to reduce the reading at which time the number
/// will be truncated to 12 digits.
/// </para>
/// </summary>
public class Readings : ASCIIString
{
const int LENGTH = 12;
public Readings() : base(LENGTH)
{
}
public Readings(byte[] response) : base(response, LENGTH)
{
}
public Readings(string value) : base(value, LENGTH)
{
}
public byte SensorID => this.bytes[0];
public ReadingSettings Setting => (ReadingSettings)this.bytes[1];
public bool Include => this.bytes[2] == 1;
public static implicit operator Readings(string value)
=> new Readings { Value = value };
}
}
@@ -0,0 +1,175 @@
namespace OmniPlus.Features
{
using System;
public class RegisterSettings : FeatureRequest
{
const int LENGTH = 13;
public RegisterSettings() : base(LENGTH)
{
}
public RegisterSettings(byte[] response) : base(response, LENGTH)
{
}
public ushort IntPart
{
get => BitConverter.ToUInt16(this.bytes, 0);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 0);
}
public ushort Fraction
{
get => BitConverter.ToUInt16(this.bytes, 2);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 2);
}
public byte Size
{
get => this.bytes[4];
set => this.bytes[4] = value;
}
public byte Range
{
get => this.bytes[5];
set => this.bytes[5] = value;
}
public byte VolumePerPulseUnit
{
get => this.bytes[6];
set => this.bytes[6] = value;
}
public byte MeterUnits
{
get => this.bytes[7];
set => this.bytes[7] = value;
}
public byte FlowUnits
{
get
{
var src = this.bytes[8].GetBits();
var dst = new byte[8];
Array.Copy(src, 0, dst, 0, 4);
return dst.ToUint8();
}
set
{
var srcIndex = 0;
var srcBits = value.GetBits();
var dstBits = this.bytes[8].GetBits();
for (int dstIndex = 0; dstIndex < 4; dstIndex++)
{
dstBits[dstIndex] = srcBits[srcIndex++];
}
this.bytes[8] = dstBits.ToUint8();
}
}
public byte FlowRate
{
get
{
var src = this.bytes[8].GetBits();
var dst = new byte[8];
Array.Copy(src, 4, dst, 0, 4);
return dst.ToUint8();
}
set
{
var srcIndex = 0;
var srcBits = value.GetBits();
var dstBits = this.bytes[8].GetBits();
for (int dstIndex = 4; dstIndex < 8; dstIndex++)
{
dstBits[dstIndex] = srcBits[srcIndex++];
}
this.bytes[8] = dstBits.ToUint8();
}
}
public sbyte FactoryCorrection
{
get => (sbyte)this.bytes[9];
set => this.bytes[9] = (byte)value;
}
public sbyte FieldCorrection
{
get => (sbyte)this.bytes[10];
set => this.bytes[10] = (byte)value;
}
public byte PulseWeight
{
get => this.bytes[11];
set => this.bytes[11] = value;
}
public byte PulseWidth
{
get
{
var src = this.bytes[12].GetBits();
var dst = new byte[8];
Array.Copy(src, 0, dst, 0, 3);
return dst.ToUint8();
}
set
{
var srcIndex = 0;
var srcBits = value.GetBits();
var dstBits = this.bytes[12].GetBits();
for (int dstIndex = 0; dstIndex < 3; dstIndex++)
{
dstBits[dstIndex] = srcBits[srcIndex++];
}
this.bytes[12] = dstBits.ToUint8();
}
}
public byte PulseUpdate
{
get
{
var src = this.bytes[12].GetBits();
var dst = new byte[8];
Array.Copy(src, 3, dst, 0, 3);
return dst.ToUint8();
}
set
{
var srcIndex = 0;
var srcBits = value.GetBits();
var dstBits = this.bytes[12].GetBits();
for (int dstIndex = 3; dstIndex < 6; dstIndex++)
{
dstBits[dstIndex] = srcBits[srcIndex++];
}
this.bytes[12] = dstBits.ToUint8();
}
}
}
}
@@ -0,0 +1,130 @@
namespace OmniPlus.Features
{
using System;
public class SystemParameters : FeatureRequest
{
const int LENGTH = 59;
public SystemParameters() : base(LENGTH)
{
this.BuildInfo = new BuildInfo();
this.ManifacturingTime = new ManifacturingTime();
this.SystemTime = new SystemTime();
this.VersionAndType = new VersionAndType();
this.BatteryVoltage = new BatteryVoltage();
}
public SystemParameters(byte[] response) : base(response, LENGTH)
{
this.BuildInfo = new BuildInfo();
this.BuildInfo.Status = this.Status;
this.BuildInfo.ToASCIIString(this.bytes, 0, 15);
this.ManifacturingTime = new ManifacturingTime();
this.ManifacturingTime.Status = this.Status;
this.ManifacturingTime.SecondsSince = BitConverter.ToUInt32(this.bytes, 16);
this.SystemTime = new SystemTime();
this.SystemTime.Status = this.Status;
this.SystemTime.SecondsSince = BitConverter.ToUInt32(this.bytes, 20);
this.RebootsCount = this.bytes[24];
this.VersionAndType = new VersionAndType();
this.VersionAndType.Status = this.Status;
this.VersionAndType.ToASCIIString(this.bytes, 25, 51);
this.BatteryVoltage = new BatteryVoltage();
this.BatteryVoltage.Status = this.Status;
this.BatteryVoltage.Volts = BitConverter.ToUInt16(this.bytes, 52);
this.BatteryVoltage.ADCCount = BitConverter.ToUInt32(this.bytes, 54);
this.FactorySealed = this.bytes[58] == 1;
this.ValidateParameters();
}
public BuildInfo BuildInfo { get; set; }
public ManifacturingTime ManifacturingTime { get; set; }
public SystemTime SystemTime { get; set; }
public byte RebootsCount { get; set; }
public VersionAndType VersionAndType { get; set; }
public BatteryVoltage BatteryVoltage { get; set; }
public bool FactorySealed { get; set; }
public bool IsValid { get; set; }
private void ValidateParameters()
{
this.IsValid = !this.FactorySealed;
if (!this.IsValid)
{
return;
}
var firmwareTokens = this.VersionAndType
?.Value
?.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
?? new string[2];
var versionString = string.Empty;
if (firmwareTokens?.Length > 0 && firmwareTokens[0]?.Length > 0)
{
versionString = firmwareTokens[0].Substring(1);
}
this.IsValid = double.TryParse(versionString, out var version) && version >= 1.23;
if (!this.IsValid)
{
return;
}
var typeString = string.Empty;
if (firmwareTokens?.Length > 1 && firmwareTokens[1]?.Length > 0)
{
typeString = firmwareTokens[1].ToUpper();
}
this.IsValid = typeString == "OMNI-01" || typeString == "OMNI-02";
if (!this.IsValid)
{
return;
}
this.IsValid = 3190 <= this.BatteryVoltage.Volts && this.BatteryVoltage.Volts <= 3750;
if (!this.IsValid)
{
return;
}
this.IsValid = this.RebootsCount != 0xFF;
if (!this.IsValid)
{
return;
}
this.IsValid = Math.Abs((DateTime.UtcNow - this.SystemTime.DateTime).Seconds) <= 700;
if (!this.IsValid)
{
return;
}
this.IsValid = Math.Abs((DateTime.UtcNow - this.ManifacturingTime.DateTime).Seconds) <= 365;
}
}
}
@@ -0,0 +1,21 @@
namespace OmniPlus.Features
{
using System;
public class SystemTime : Epoch20000101
{
public SystemTime() : base()
{
}
public SystemTime(byte[] response) : base(response)
{
}
public static implicit operator SystemTime(DateTime dateTime)
=> new SystemTime
{
DateTime = dateTime,
};
}
}

Some files were not shown because too many files have changed in this diff Show More