omni progress

This commit is contained in:
Stoyan Zlatev
2023-11-09 08:59:09 +01:00
parent 9a22cb9d0e
commit 8796272107
109 changed files with 3831 additions and 2684 deletions
+7 -211
View File
@@ -171,27 +171,19 @@ 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.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}") = "OmniPlus", "OmniPlus", "{D1CAF04E-407D-4F01-B588-54815EA88B0D}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OmniPlus", "OmniPlus", "{68323534-4337-4E3A-89BC-11D8BB55343A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NamedPipes", "..\..\..\..\Desktop\OmniPlus\NamedPipes\NamedPipes.csproj", "{0CC5A97F-E1CD-412B-AFFE-B256FDB7DC19}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NamedPipes", "NamedPipes\NamedPipes.csproj", "{0CC5A97F-E1CD-412B-AFFE-B256FDB7DC19}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmniPlus", "..\..\..\..\Desktop\OmniPlus\OmniPlus\OmniPlus.csproj", "{F8D84B9A-0FCF-4083-B067-8C39B7314152}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmniPlus", "OmniPlus\OmniPlus.csproj", "{F8D84B9A-0FCF-4083-B067-8C39B7314152}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmniPlus.UI", "..\..\..\..\Desktop\OmniPlus\OmniPlus.UI\OmniPlus.UI.csproj", "{6518211A-E83F-4171-97C4-A61FCF66D6E0}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmniPlus.UI", "OmniPlus.UI\OmniPlus.UI.csproj", "{6518211A-E83F-4171-97C4-A61FCF66D6E0}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
@@ -3939,198 +3931,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
{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
@@ -4592,16 +4392,12 @@ 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}
{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}
{0CC5A97F-E1CD-412B-AFFE-B256FDB7DC19} = {D1CAF04E-407D-4F01-B588-54815EA88B0D}
{F8D84B9A-0FCF-4083-B067-8C39B7314152} = {D1CAF04E-407D-4F01-B588-54815EA88B0D}
{6518211A-E83F-4171-97C4-A61FCF66D6E0} = {D1CAF04E-407D-4F01-B588-54815EA88B0D}
{0CC5A97F-E1CD-412B-AFFE-B256FDB7DC19} = {68323534-4337-4E3A-89BC-11D8BB55343A}
{F8D84B9A-0FCF-4083-B067-8C39B7314152} = {68323534-4337-4E3A-89BC-11D8BB55343A}
{6518211A-E83F-4171-97C4-A61FCF66D6E0} = {68323534-4337-4E3A-89BC-11D8BB55343A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4BCB7B69-696C-436A-86F7-C91EA5588164}
+150
View File
@@ -0,0 +1,150 @@
using System.ComponentModel;
using System.IO.Pipes;
using System;
using System.Threading;
namespace NamedPipes
{
public abstract class NamedPipe
{
protected const string PIPE_NAME = "NamedPipes";
protected const byte FLOW_REQUEST = 1;
protected const byte DATA_REQUEST = 2;
protected const byte MSG_LENGTH = 9;
protected PipeStream pipe;
private readonly BackgroundWorker worker;
public NamedPipe()
{
this.worker = new BackgroundWorker();
this.worker.DoWork += this.Run;
}
public event Action Connected;
public event Action Disconnected;
public event Action<double> DataRequest;
public event Action<double> FlowRequest;
public void Disconnect()
{
this.pipe?.Dispose();
this.worker?.Dispose();
}
public void Connect()
=> this.worker.RunWorkerAsync();
public double RequestReference()
{
var completed = false;
var reference = 0D;
var timeout = 60_000;
var delay = 1000;
void DataRequested(double val)
{
completed = true;
reference = val;
}
this.DataRequest += DataRequested;
this.SendMessage(reference, DATA_REQUEST);
while (!completed && timeout > 0)
{
Thread.Sleep(delay);
timeout -= delay;
}
this.FlowRequest -= DataRequested;
return reference;
}
public void RequestFlowRate(double value)
{
var completed = false;
var timeout = 60_000;
var delay = 1000;
void FlowRequested(double _) => completed = true;
this.FlowRequest += FlowRequested;
this.SendMessage(value, FLOW_REQUEST);
while (!completed && timeout > 0)
{
Thread.Sleep(delay);
timeout -= delay;
}
this.FlowRequest -= FlowRequested;
}
protected void SendMessage(double value, byte endpoint)
{
if (this.pipe.IsConnected)
{
var message = new byte[MSG_LENGTH];
message[0] = endpoint;
BitConverter
.GetBytes(value)
.CopyTo(message, 1);
this.pipe.Write(message, 0, message.Length);
}
}
protected virtual void Run(object sender, DoWorkEventArgs args)
{
this.Connected?.Invoke();
var buffer = new byte[byte.MaxValue];
while (this.pipe.IsConnected)
{
var asyncResult = this.pipe.BeginRead(buffer, 0, byte.MaxValue, this.EndRead, buffer);
if (asyncResult.AsyncWaitHandle.WaitOne())
{
continue;
}
else
{
break;
}
}
if (!this.pipe.IsConnected)
{
this.Disconnected?.Invoke();
}
}
private void EndRead(IAsyncResult asyncResult)
{
if (this.pipe.IsConnected && asyncResult.AsyncState is byte[] buffer)
{
var readLength = this.pipe.EndRead(asyncResult);
if (readLength > 0 && buffer.Length >= readLength)
{
var value = BitConverter.ToDouble(buffer, 1);
switch (buffer[0])
{
case FLOW_REQUEST: this.FlowRequest?.Invoke(value); break;
case DATA_REQUEST: this.DataRequest?.Invoke(value); break;
}
}
}
}
}
}
+28
View File
@@ -0,0 +1,28 @@
using System.ComponentModel;
using System.IO.Pipes;
namespace NamedPipes
{
public class NamedPipeClient : NamedPipe
{
protected override void Run(object sender, DoWorkEventArgs args)
{
try
{
var pipe = new NamedPipeClientStream(
serverName: ".",
pipeName: PIPE_NAME,
direction: PipeDirection.InOut,
options: PipeOptions.Asynchronous);
this.pipe = pipe;
pipe.Connect();
base.Run(sender, args);
}
catch
{
base.Disconnect();
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
using System.ComponentModel;
using System.IO.Pipes;
namespace NamedPipes
{
public class NamedPipeServer : NamedPipe
{
protected override void Run(object sender, DoWorkEventArgs args)
{
try
{
var pipe = new NamedPipeServerStream(
pipeName: PIPE_NAME,
maxNumberOfServerInstances: 1,
direction: PipeDirection.InOut,
transmissionMode: PipeTransmissionMode.Byte,
options: PipeOptions.Asynchronous);
this.pipe = pipe;
pipe.WaitForConnection();
base.Run(sender, args);
}
catch
{
base.Disconnect();
}
}
}
}
@@ -4,11 +4,11 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C27BA66C-C3A7-48A2-A644-CBA77E28E531}</ProjectGuid>
<ProjectGuid>{0CC5A97F-E1CD-412B-AFFE-B256FDB7DC19}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SIRTBroadcaster.Abstraction</RootNamespace>
<AssemblyName>SIRTBroadcaster.Abstraction</AssemblyName>
<RootNamespace>NamedPipes</RootNamespace>
<AssemblyName>NamedPipes</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
@@ -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="NamedPipe.cs" />
<Compile Include="NamedPipeClient.cs" />
<Compile Include="NamedPipeServer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SIRTExtensions.cs" />
<Compile Include="SIRTFixed.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</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("NamedPipes")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SIRTBroadcaster.UI")]
[assembly: AssemblyProduct("NamedPipes")]
[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("0cc5a97f-e1cd-412b-affe-b256fdb7dc19")]
// Version information for an assembly consists of the following four values:
//
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="COMS" value="COM4, COM, COM, COM, COM, COM, COM, COM"/>
<add key="OMNIDB" value="Server=SLASQL01.emea.sensus.net; Database=AuftragKopie; User ID=sa; Password=sqlserver;"/>
</appSettings>
</configuration>
@@ -4,10 +4,10 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2550B77D-D975-4A50-9C6A-526D4E07754D}</ProjectGuid>
<ProjectGuid>{6518211A-E83F-4171-97C4-A61FCF66D6E0}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>SIRTBroadcaster.UI</RootNamespace>
<AssemblyName>SIRTBroadcaster.UI</AssemblyName>
<RootNamespace>OmniPlus.UI</RootNamespace>
<AssemblyName>OmniPlus.UI</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
@@ -33,9 +33,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.Configuration" />
<Reference Include="System.Core" />
@@ -48,27 +45,18 @@
<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>
</ItemGroup>
<ItemGroup>
<Compile Include="MainForm.cs">
<Compile Include="OmniPlusUI.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
<Compile Include="OmniPlusUI.Designer.cs">
<DependentUpon>OmniPlusUI.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 Include="OmniPlusUI.resx">
<DependentUpon>OmniPlusUI.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
@@ -79,7 +67,6 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -94,17 +81,9 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SIRTBroadcaster.Abstraction\SIRTBroadcaster.Abstraction.csproj">
<Project>{c27ba66c-c3a7-48a2-a644-cba77e28e531}</Project>
<Name>SIRTBroadcaster.Abstraction</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" />
+131
View File
@@ -0,0 +1,131 @@
namespace OmniPlus.UI
{
partial class OmniPlusUI
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.layout = new System.Windows.Forms.TableLayoutPanel();
this.navbar = new System.Windows.Forms.TableLayoutPanel();
this.pruefungStartBTN = new System.Windows.Forms.Button();
this.body = new System.Windows.Forms.TableLayoutPanel();
this.pruefungBackground = new System.ComponentModel.BackgroundWorker();
this.layout.SuspendLayout();
this.navbar.SuspendLayout();
this.SuspendLayout();
//
// layout
//
this.layout.ColumnCount = 1;
this.layout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.layout.Controls.Add(this.navbar, 0, 1);
this.layout.Controls.Add(this.body, 0, 0);
this.layout.Dock = System.Windows.Forms.DockStyle.Fill;
this.layout.Location = new System.Drawing.Point(0, 0);
this.layout.Name = "layout";
this.layout.RowCount = 2;
this.layout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.layout.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.layout.Size = new System.Drawing.Size(1055, 560);
this.layout.TabIndex = 0;
//
// navbar
//
this.navbar.AutoSize = true;
this.navbar.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.navbar.ColumnCount = 3;
this.navbar.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.navbar.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.navbar.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.navbar.Controls.Add(this.pruefungStartBTN, 2, 0);
this.navbar.Dock = System.Windows.Forms.DockStyle.Fill;
this.navbar.Location = new System.Drawing.Point(0, 523);
this.navbar.Margin = new System.Windows.Forms.Padding(0);
this.navbar.Name = "navbar";
this.navbar.Padding = new System.Windows.Forms.Padding(3);
this.navbar.RowCount = 2;
this.navbar.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.navbar.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.navbar.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.navbar.Size = new System.Drawing.Size(1055, 37);
this.navbar.TabIndex = 0;
//
// pruefungStartBTN
//
this.pruefungStartBTN.AutoSize = true;
this.pruefungStartBTN.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.pruefungStartBTN.Dock = System.Windows.Forms.DockStyle.Fill;
this.pruefungStartBTN.Location = new System.Drawing.Point(927, 6);
this.pruefungStartBTN.Name = "pruefungStartBTN";
this.navbar.SetRowSpan(this.pruefungStartBTN, 2);
this.pruefungStartBTN.Size = new System.Drawing.Size(122, 25);
this.pruefungStartBTN.TabIndex = 0;
this.pruefungStartBTN.Text = "Prüfung starten";
this.pruefungStartBTN.UseVisualStyleBackColor = true;
this.pruefungStartBTN.Click += new System.EventHandler(this.PruefungStartBTN_Click);
//
// body
//
this.body.ColumnCount = 1;
this.body.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.body.Dock = System.Windows.Forms.DockStyle.Fill;
this.body.Location = new System.Drawing.Point(0, 0);
this.body.Margin = new System.Windows.Forms.Padding(0);
this.body.Name = "body";
this.body.Padding = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.body.RowCount = 1;
this.body.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.body.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 522F));
this.body.Size = new System.Drawing.Size(1055, 523);
this.body.TabIndex = 1;
//
// OmniPlusUI
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1055, 560);
this.Controls.Add(this.layout);
this.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Name = "OmniPlusUI";
this.Text = "OMNI Plus";
this.layout.ResumeLayout(false);
this.layout.PerformLayout();
this.navbar.ResumeLayout(false);
this.navbar.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel layout;
private System.Windows.Forms.TableLayoutPanel navbar;
private System.Windows.Forms.TableLayoutPanel body;
private System.Windows.Forms.Button pruefungStartBTN;
private System.ComponentModel.BackgroundWorker pruefungBackground;
}
}
+249
View File
@@ -0,0 +1,249 @@
using OmniPlus.UI.Inspection;
using System;
using System.ComponentModel;
using System.Configuration;
using System.Drawing;
using System.Windows.Forms;
namespace OmniPlus.UI
{
public partial class OmniPlusUI : Form
{
private readonly OmniPlusConnectionsPool connectionsPool;
public OmniPlusUI()
{
this.InitializeComponent();
var omniDatabase = ConfigurationManager.AppSettings.Get("OMNIDB");
this.connectionsPool = new OmniPlusConnectionsPool(omniDatabase);
this.HandleCreated += this.OmniPlusUI_HandleCreated;
this.HandleDestroyed += this.OmniPlusUI_HandleDestroyed;
}
private void OmniPlusUI_HandleDestroyed(object _, EventArgs _1)
{
this.connectionsPool.Dispose();
this.connectionsPool.StateChanged -= this.ConnectionsPool_StateChanged;
this.pruefungBackground.DoWork -= this.PruefungBackground_DoWork;
}
private void OmniPlusUI_HandleCreated(object _, EventArgs _1)
{
this.connectionsPool.StateChanged += this.ConnectionsPool_StateChanged;
this.pruefungBackground.DoWork += this.PruefungBackground_DoWork;
this.InitializeBody();
var portNames = (ConfigurationManager
.AppSettings
.Get("COMS") ?? string.Empty)
.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
this.connectionsPool.InitializeInspection(portNames);
}
private void PruefungStartBTN_Click(object _, EventArgs _1)
=> this.pruefungBackground.RunWorkerAsync();
private void PruefungBackground_DoWork(object _, DoWorkEventArgs _1)
{
this.Invoke(new Action(() =>
{
this.Cursor = Cursors.WaitCursor;
this.pruefungStartBTN.Enabled = false;
}));
this.ClearBody();
this.connectionsPool.StartInspection();
this.Invoke(new Action(() =>
{
this.Cursor = Cursors.Default;
this.pruefungStartBTN.Enabled = true;
}));
}
private void ConnectionsPool_StateChanged(int column, bool? succeeded, string header, string value)
{
this.body.Invoke(new Action(() =>
{
var headerIndex = this.GetRowIndex(header);
var columnIndex = headerIndex + column;
var controls = this.body.Controls;
var controlsCount = controls.Count;
if (controls[headerIndex] is Label rowHeader)
{
rowHeader.Text = header;
rowHeader.TextAlign = ContentAlignment.MiddleLeft;
rowHeader.BackColor = SystemColors.ControlLight;
rowHeader.ForeColor = SystemColors.ControlText;
}
if (controls[columnIndex] is Label columnLabel)
{
if (string.IsNullOrWhiteSpace(value))
{
value = "---";
}
columnLabel.Text = value;
columnLabel.BackColor = SystemColors.Window;
if (headerIndex == 0)
{
columnLabel.BackColor = SystemColors.ControlLight;
}
columnLabel.ForeColor = SystemColors.ControlText;
if (headerIndex > 0 && columnIndex > 0)
{
if (succeeded == true)
{
columnLabel.ForeColor = Color.DarkGreen;
}
else if (succeeded == false)
{
columnLabel.ForeColor = Color.Red;
}
else
{
columnLabel.ForeColor = Color.Gray;
}
}
}
}));
}
private int GetRowIndex(string header)
{
var controls = this.body.Controls;
var controlsCount = controls.Count;
var cols = this.body.ColumnCount;
var rows = this.body.RowCount;
var rowIndex = int.MinValue;
int row;
for (row = 0; row < rows; row++)
{
var headerIndex = row * cols;
if (headerIndex >= controlsCount)
{
break;
}
if (controls[headerIndex] is Label label)
{
var labelText = label.Text?.Trim()?.ToLower();
var headerText = header?.Trim()?.ToLower();
if (string.IsNullOrWhiteSpace(labelText) || labelText == headerText)
{
rowIndex = headerIndex;
break;
}
}
else break;
}
if (rowIndex == int.MinValue)
{
rowIndex = (rows - 1) * cols;
}
return rowIndex;
}
private void InitializeBody()
{
this.body.Invoke(new Action(() =>
{
var cols = 9;
var rows = 31;
this.body.RowCount = 0;
this.body.ColumnCount = 0;
this.body.Controls.Clear();
this.body.RowStyles.Clear();
this.body.ColumnStyles.Clear();
var bold = new Font(this.body.Font, FontStyle.Bold);
for (int row = 0; row < rows; row++)
{
var firstRow = row == 0;
this.body.RowCount++;
this.body.RowStyles.Add(new RowStyle(SizeType.AutoSize));
for (int col = 0; col < cols; col++)
{
var firstCol = col == 0;
var lastCol = col == cols - 1;
if (firstRow)
{
this.body.ColumnCount++;
this.body.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, firstCol ? 100F : 65F));
}
var color = firstCol || firstRow ? SystemColors.ControlLight : SystemColors.Window;
var label = new Label
{
Dock = DockStyle.Fill,
Padding = new Padding(3),
Margin = new Padding(0, 0, lastCol ? 0 : 3, 3),
TextAlign = ContentAlignment.MiddleCenter,
BackColor = color,
ForeColor = color
};
if (firstCol || firstRow)
{
label.Font = bold;
}
this.body.Controls.Add(label, col, row);
}
}
this.body.RowCount++;
this.body.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
}));
}
private void ClearBody()
{
this.body.Invoke(new Action(() =>
{
var rows = this.body.RowCount;
var cols = this.body.ColumnCount;
var controls = this.body.Controls;
for (int row = 1; row < rows; row++)
{
var offset = Math.Max(row - 1, 1) * cols;
for (int col = 1; col < cols; col++)
{
if (controls[offset + col] is Label label)
{
label.Text = null;
}
}
}
}));
}
}
}
@@ -117,4 +117,10 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="pruefungBackground.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>64</value>
</metadata>
</root>
+16
View File
@@ -0,0 +1,16 @@
using System;
using System.Windows.Forms;
namespace OmniPlus.UI
{
public static class Program
{
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new OmniPlusUI());
}
}
}
@@ -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.Host")]
[assembly: AssemblyTitle("OmniPlus.UI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SIRTBroadcaster.Host")]
[assembly: AssemblyProduct("OmniPlus.UI")]
[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("a9d1a99d-6e55-4394-86ad-b5c53e9225eb")]
[assembly: Guid("6518211a-e83f-4171-97c4-a61fcf66d6e0")]
// Version information for an assembly consists of the following four values:
//
@@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace SIRTBroadcaster.UI.Properties
namespace OmniPlus.UI.Properties
{
@@ -44,7 +44,7 @@ namespace SIRTBroadcaster.UI.Properties
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SIRTBroadcaster.UI.Properties.Resources", typeof(Resources).Assembly);
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OmniPlus.UI.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
@@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace SIRTBroadcaster.UI.Properties
namespace OmniPlus.UI.Properties
{
@@ -0,0 +1,98 @@
using OmniPlus.Enums;
using OmniPlus.Hanlers;
using System;
using System.IO.Ports;
using System.Threading;
namespace OmniPlus.Connections
{
internal class IrdaConnection : SerialPortConnection
{
protected event DataReceivedHandler MessageReceived;
public IrdaConnection(string portName)
{
this.Options.PortName = portName;
this.Options.BaudRate = BaudRate.K115200;
this.Options.DataBits = DataBits.X8;
this.Options.Parity = Parity.None;
this.Options.StopBits = StopBits.One;
this.Options.LogFile = $".\\IRDA\\[{portName}].txt";
}
public byte[] SendMessage(byte[] command)
{
var response = new byte[0];
var received = false;
if (command is null)
{
return response;
}
void MessageReceivedHandler(byte[] bytes)
{
response = bytes
.FromIrdaMessage()
.FromUI1236Message();
received = true;
}
this.MessageReceived += MessageReceivedHandler;
this.Write(1, 1, 1, 1);
var request = command
.ToUI1236Message()
.ToIrdaMessage();
var sleep = 5000;
var delay = 500;
this.Write(request);
while (!received && sleep >= 0)
{
sleep -= delay;
Thread.Sleep(delay);
}
this.MessageReceived -= MessageReceivedHandler;
return response;
}
protected override void SerialPortConnection_DataReceived(byte[] bytes)
{
var message = default(byte[]);
var length = bytes.Length;
var start = 0;
while (start < bytes.Length)
{
if (bytes[start] == OmniPlusExtensions.IRDA_START)
{
try
{
var messageLength = bytes[start + 2] * 2;
messageLength += OmniPlusExtensions.IRDA_MIN_LENGTH;
message = new byte[messageLength];
Array.Copy(bytes, start, message, 0, messageLength);
}
catch (Exception e)
{
this.SerialPortConnection_LogMessage(e.ToString());
}
break;
}
start++;
}
this.MessageReceived?.Invoke(message);
}
}
}
@@ -0,0 +1,209 @@
using OmniPlus.Enums;
using OmniPlus.Hanlers;
using OmniPlus.Options;
using System;
using System.IO;
using System.IO.Ports;
namespace OmniPlus.Connections
{
internal abstract class SerialPortConnection
{
protected event StateChangedEventHandler StateChanged;
protected event DataReceivedHandler DataReceived;
protected event LogMessageEventHandler LogMessage;
private SerialPort serialPort;
private SerialPortState state;
protected SerialPortConnection()
=> this.Options = new SerialPortOptions();
protected SerialPortOptions Options { get; }
public bool Connected => this.state == SerialPortState.Open;
public virtual void Close()
{
try
{
if (this.serialPort != null)
{
this.serialPort.DataReceived -= this.SerialPort_DataReceived;
this.serialPort.Disposed -= this.SerialPort_Disposed;
this.serialPort.ErrorReceived -= this.SerialPort_ErrorReceived;
this.serialPort.PinChanged -= this.SerialPort_PinChanged;
}
this.serialPort?.Close();
this.serialPort?.Dispose();
}
catch (Exception e)
{
this.StateChanged?.Invoke(SerialPortState.ErrorReceived, e.ToString());
}
this.serialPort = null;
this.state = SerialPortState.Closed;
this.StateChanged?.Invoke(this.state, $"{this.Options.PortName} closed.");
if (this.LogMessage != null)
{
foreach (var @delegate in this.LogMessage.GetInvocationList())
{
if (@delegate is LogMessageEventHandler eventHandler)
{
this.LogMessage -= eventHandler;
}
}
}
if (this.StateChanged != null)
{
foreach (var @delegate in this.StateChanged.GetInvocationList())
{
if (@delegate is LogMessageEventHandler eventHandler)
{
this.LogMessage -= eventHandler;
}
}
}
if (this.DataReceived != null)
{
foreach (var @delegate in this.DataReceived.GetInvocationList())
{
if (@delegate is LogMessageEventHandler eventHandler)
{
this.LogMessage -= eventHandler;
}
}
}
}
public virtual void Open()
{
this.Close();
try
{
var fileInfo = new FileInfo(this.Options.LogFile);
fileInfo.Directory.Create();
File.AppendAllText(this.Options.LogFile, string.Empty);
this.LogMessage += this.SerialPortConnection_LogMessage;
}
catch (Exception e)
{
this.state = SerialPortState.ErrorReceived;
this.StateChanged?.Invoke(this.state, $"{this.Options.PortName}: {e}");
}
try
{
this.serialPort = new SerialPort
{
PortName = this.Options.PortName,
BaudRate = (int)this.Options.BaudRate,
DataBits = (int)this.Options.DataBits,
Parity = this.Options.Parity,
StopBits = this.Options.StopBits,
RtsEnable = this.Options.RtsEnabled,
DtrEnable = this.Options.DtrEnabled
};
this.serialPort.DataReceived += this.SerialPort_DataReceived;
this.serialPort.Disposed += this.SerialPort_Disposed;
this.serialPort.ErrorReceived += this.SerialPort_ErrorReceived;
this.serialPort.PinChanged += this.SerialPort_PinChanged;
this.DataReceived += this.SerialPortConnection_DataReceived;
this.StateChanged += this.SerialPortConnection_StateChanged;
this.serialPort.Open();
this.state = SerialPortState.Open;
this.StateChanged?.Invoke(this.state
, $"{this.Options.PortName} opened"
+ $", {this.Options.BaudRate}"
+ $", {this.Options.DataBits}"
+ $", {this.Options.Parity}"
+ $", {this.Options.StopBits}");
}
catch (Exception e)
{
this.state = SerialPortState.ErrorReceived;
this.StateChanged?.Invoke(this.state, $"{this.Options.PortName}: {e}");
this.Close();
}
}
protected void Write(params byte[] message)
{
if (this.Connected && message.Length > 0)
{
this.serialPort.Write(message, 0, message.Length);
}
this.LogMessage?.Invoke($"TX: {BitConverter.ToString(message)}");
}
protected abstract void SerialPortConnection_DataReceived(byte[] bytes);
protected void SerialPortConnection_LogMessage(string message)
=> File.AppendAllText(this.Options.LogFile, $"{message}{Environment.NewLine}");
protected void SerialPortConnection_StateChanged(SerialPortState state, string message)
=> File.AppendAllText(this.Options.LogFile, $"[{state}] {message}{Environment.NewLine}");
private void SerialPort_PinChanged(object sender, SerialPinChangedEventArgs args)
{
this.state = SerialPortState.PinChanged;
this.StateChanged?.Invoke(this.state, $"{this.Options.PortName} {args.EventType}.");
this.Close();
}
private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs args)
{
this.state = SerialPortState.ErrorReceived;
this.StateChanged?.Invoke(this.state, $"{this.Options.PortName} {args.EventType}.");
this.Close();
}
private void SerialPort_Disposed(object sender, EventArgs args)
{
this.state = SerialPortState.Disposed;
this.StateChanged?.Invoke(this.state, $"{this.Options.PortName} disposed.");
this.Close();
}
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs args)
{
if (this.Connected && sender is SerialPort port && port.BytesToRead > 0)
{
var bytes = new byte[port.BytesToRead];
var lock_object = new object();
lock (lock_object)
{
port.Read(bytes, 0, port.BytesToRead);
}
this.DataReceived?.Invoke(bytes);
this.LogMessage?.Invoke($"RX: {BitConverter.ToString(bytes)}");
}
}
}
}
@@ -0,0 +1,92 @@
using OmniPlus.Enums;
using OmniPlus.Hanlers;
using System;
using System.IO.Ports;
using System.Threading;
namespace OmniPlus.Connections
{
internal class UniProConnection : SerialPortConnection
{
protected event DataReceivedHandler MessageReceived;
public UniProConnection(string portName)
{
this.Options.PortName = portName;
this.Options.BaudRate = BaudRate.K2400;
this.Options.DataBits = DataBits.X8;
this.Options.Parity = Parity.None;
this.Options.StopBits = StopBits.One;
this.Options.LogFile = $".\\UniPro\\[{portName}].txt";
}
public byte[] SendMessage(byte[] command)
{
var response = new byte[0];
var received = false;
if (command is null)
{
return response;
}
void MessageReceivedHandler(byte[] bytes)
{
response = bytes.FromUniProMessage();
received = true;
}
this.MessageReceived += MessageReceivedHandler;
var request = command.ToUniProMessage();
var sleep = 5000;
var delay = 500;
this.Write(request);
while (!received && sleep >= 0)
{
sleep -= delay;
Thread.Sleep(delay);
}
this.MessageReceived -= MessageReceivedHandler;
return response;
}
protected override void SerialPortConnection_DataReceived(byte[] bytes)
{
var message = default(byte[]);
var length = bytes.Length;
var start = 0;
while (start < bytes.Length)
{
if (bytes[start] == OmniPlusExtensions.UNIPRO_START)
{
try
{
var messageLength = bytes[start + 2];
messageLength += OmniPlusExtensions.UNIPRO_MIN_LENGTH;
message = new byte[messageLength];
Array.Copy(bytes, start, message, 0, messageLength);
}
catch (Exception e)
{
this.SerialPortConnection_LogMessage(e.ToString());
}
break;
}
start++;
}
this.MessageReceived?.Invoke(message);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
namespace OmniPlus.Enums
{
public enum BaudRate
{
K300 = 300,
K600 = 600,
K1200 = 1200,
K2400 = 2400,
K4800 = 4800,
K9600 = 9600,
K19200 = 19200,
K38400 = 38400,
K57600 = 57600,
K115200 = 115200,
K230400 = 230400,
K460800 = 460800,
K921600 = 921600
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace OmniPlus.Enums
{
public enum DataBits
{
X5 = 5,
X6 = 6,
X7 = 7,
X8 = 8
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace OmniPlus.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,
}
}
+16
View File
@@ -0,0 +1,16 @@
namespace OmniPlus.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,
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace OmniPlus.Enums
{
public enum SerialPortState
{
Closed,
Disposed,
PinChanged,
ErrorReceived,
Open
}
}
+52
View File
@@ -0,0 +1,52 @@
namespace OmniPlus.Enums
{
public enum Status : byte
{
/// <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
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace OmniPlus.Enums
{
public enum TimeUnits : byte
{
Milliseconds = 0,
Seconds = 1,
Minutes = 2,
Hours = 3,
Days = 4,
Years = 5,
}
}
+41
View File
@@ -0,0 +1,41 @@
namespace OmniPlus.Features
{
using System.Text;
public class ASCIIString : FeatureRequest
{
public ASCIIString(int length) : base(length)
{
}
public ASCIIString(byte[] response, int length) : base(response, length)
{
}
public string Value
{
get => this.GetValue();
set => this.SetValue(value);
}
private string GetValue()
=> Encoding.ASCII
.GetString(this.bytes)
.Trim();
private void SetValue(string value)
{
this.bytes.Clear();
var factoryID = value
?.Substring(0, this.length)
?? string.Empty;
Encoding.ASCII
.GetBytes(factoryID)
.CopyTo(this.bytes, 0);
}
}
}
@@ -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);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
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 = 14;
public BuildInfo() : base(LENGTH)
{
}
public BuildInfo(byte[] response) : base(response, LENGTH)
{
}
}
}
@@ -0,0 +1,68 @@
using System;
namespace OmniPlus.Features
{
public class ChamberCalibration : FeatureRequest
{
public const byte ACTIVATE_TEST = 0x00;
public const byte REQUEST_RESULTS = 0x01;
public const byte TEST_ACTIVATED = 0x00;
public const byte TEST_FAILED = 0x01;
public const byte TEST_COMPLETED = 0x02;
const int LENGTH = 5;
public ChamberCalibration() : base(LENGTH)
{
}
public ChamberCalibration(byte[] response) : base(response, LENGTH)
{
}
/// <summary>
/// Request Response
/// 0 – Activate Factory Calibration Test Test Activation Successful
/// 1 – Request Factory Calibration Test Results Test Failed (Timeout)
/// 2 - ........................................ Test Successfully Completed
/// </summary>
public byte Control
{
get => this.bytes[0];
set => this.bytes[0] = value;
}
/// <summary>
/// <para>
/// Request: Number of Rotations to collect. (not required if Requesting Calibration results) (Limited to 1 to 5000 rotations)
/// </para>
/// <para>
/// 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.
/// </para>
/// </summary>
public ushort Rotations
{
get => BitConverter.ToUInt16(this.bytes, 1);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 1);
}
/// <summary>
/// <para>
/// Request: Maximum Time command is supposed to take to execute - 1 to 3600 Seconds.
/// </para>
/// <para>
/// 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.
/// </para>
/// </summary>
public ushort Duration
{
get => BitConverter.ToUInt16(this.bytes, 3);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 3);
}
}
}
@@ -0,0 +1,60 @@
namespace OmniPlus.Features
{
using System;
public class ConfigurationParameters : FeatureRequest
{
const int LENGTH = 62;
public ConfigurationParameters() : base(LENGTH)
{
}
public ConfigurationParameters(byte[] response) : base(response, LENGTH)
{
this.ProgrammableID = new ProgrammableID();
this.ProgrammableID.Status = this.Status;
this.ProgrammableID.Value = this.bytes.ToASCIIString(0, 20);
this.FactoryID = new FactoryID();
this.FactoryID.Status = this.Status;
this.FactoryID.Value = this.bytes.ToASCIIString(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.Value = this.bytes.ToASCIIString(36, 45);
this.OptionalUniDirFields = new OptionalUniDirFields();
this.OptionalUniDirFields.Status = this.Status;
this.OptionalUniDirFields.Past(this.bytes, 46);
this.AlartPersistencePeriod = this.bytes[50];
this.DataLogIntervalMinutes = BitConverter.ToUInt16(this.bytes, 51);
this.DeviceID = new DeviceID();
this.Readings.Status = this.Status;
this.Readings.Value = this.bytes.ToASCIIString(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 AlartPersistencePeriod { get; set; }
public ushort DataLogIntervalMinutes { get; set; }
public DeviceID DeviceID { get; set; }
}
}
+19
View File
@@ -0,0 +1,19 @@
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)
{
}
}
}
+15
View File
@@ -0,0 +1,15 @@
namespace OmniPlus.Features
{
public class DeviceID : ASCIIString
{
const int LENGTH = 9;
public DeviceID() : base(LENGTH)
{
}
public DeviceID(byte[] response) : base(response, LENGTH)
{
}
}
}
+31
View File
@@ -0,0 +1,31 @@
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;
}
}
}
+16
View File
@@ -0,0 +1,16 @@
namespace OmniPlus.Features
{
public class FactoryID : ASCIIString
{
const int LENGTH = 12;
public FactoryID() : base(LENGTH)
{
}
public FactoryID(byte[] response) : base(response, LENGTH)
{
}
}
}
@@ -0,0 +1,29 @@
namespace OmniPlus.Features
{
public class FeatureRequest : FeatureResponse
{
protected readonly int length;
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;
}
}
}
}
@@ -0,0 +1,34 @@
using OmniPlus.Enums;
using System;
namespace OmniPlus.Features
{
public class FeatureResponse
{
protected readonly byte[] bytes;
public FeatureResponse(int length = 0)
=> this.bytes = new byte[length];
public FeatureResponse(byte[] response, int length = 0) : this(length)
{
if (response != null )
{
this.Status = (Status)response[0];
if (response.Length > 1 && response.Length >= length)
{
Array.Copy(response, 1, this.bytes, 0, length);
}
}
}
public Status Status { get; set; }
public bool Succeeded => this.Status == Status.Completed;
public static implicit operator byte[](FeatureResponse response)
=> response?.bytes ?? new byte[0];
}
}
+324
View File
@@ -0,0 +1,324 @@
namespace OmniPlus.Features
{
using static System.Collections.Specialized.BitVector32;
using System.Collections.Generic;
using System.Security.Claims;
using System.Security.Policy;
using System;
internal 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-1203’s 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 response’s ;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 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;
/// <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;
}
}
+43
View File
@@ -0,0 +1,43 @@
using System;
namespace OmniPlus.Features
{
public class InputVolume : FeatureRequest
{
const int LENGTH = 6;
public InputVolume() : base(LENGTH)
{
}
public InputVolume(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 int Factor { get; set; } = 100;
}
}
@@ -0,0 +1,6 @@
namespace OmniPlus.Features
{
public class ManifacturingTime : Epoch20000101
{
}
}
@@ -0,0 +1,27 @@
namespace OmniPlus.Features
{
using System;
/// <summary>
/// TODO: Need more investigation of the purpose
/// </summary>
public class OptionalUniDirFields : FeatureRequest
{
const int LENGTH = 4;
public OptionalUniDirFields() : base(LENGTH)
{
}
public OptionalUniDirFields(byte[] response) : base(response, LENGTH)
{
}
public void Past(byte[] bytes, int start)
{
this.bytes.Clear();
Array.Copy(bytes, start, this.bytes, 0, 4);
}
}
}
@@ -0,0 +1,18 @@
namespace OmniPlus.Features
{
using System.Text;
public class ProgrammableID : ASCIIString
{
const int LENGTH = 20;
public ProgrammableID() : base(LENGTH)
{
}
public ProgrammableID(byte[] response) : base(response, LENGTH)
{
}
}
}
@@ -0,0 +1,47 @@
using System;
namespace OmniPlus.Features
{
/// <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
*/
+52
View File
@@ -0,0 +1,52 @@
namespace OmniPlus.Features
{
using OmniPlus.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];
}
}
+27
View File
@@ -0,0 +1,27 @@
namespace OmniPlus.Features
{
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;
}
}
}
+28
View File
@@ -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.
}
}
+39
View File
@@ -0,0 +1,39 @@
using OmniPlus.Enums;
namespace OmniPlus.Features
{
/// <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 = 2;
public ReadingPreset() : base(LENGTH)
{
}
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 @@
using System;
namespace OmniPlus.Features
{
/// <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
*/
+31
View File
@@ -0,0 +1,31 @@
using OmniPlus.Enums;
namespace OmniPlus.Features
{
/// <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;
}
}
}
+52
View File
@@ -0,0 +1,52 @@
using OmniPlus.Enums;
using System.Text;
namespace OmniPlus.Features
{
/// <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 = 8;
public Readings() : base(LENGTH)
{
}
public Readings(byte[] response) : base(response, LENGTH)
{
}
public byte SensorID => this.bytes[0];
public ReadingSettings Setting => (ReadingSettings)this.bytes[1];
public bool Include => this.bytes[2] == 1;
}
}
@@ -0,0 +1,41 @@
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;
}
}
}
@@ -0,0 +1,60 @@
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.Value = this.bytes.ToASCIIString(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.Value = this.bytes.ToASCIIString(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;
}
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; }
}
}
+13
View File
@@ -0,0 +1,13 @@
namespace OmniPlus.Features
{
public class SystemTime : Epoch20000101
{
public SystemTime()
{
}
public SystemTime(byte[] response) : base(response)
{
}
}
}
@@ -0,0 +1,25 @@
namespace OmniPlus.Features
{
/// <summary>
/// Protocol version is at least "R1.23".
/// Device Type ID String is "OMNI-01".
/// Software version follows the NA2W FlexNet format; e.g. "R1.0.0A".
/// <para>
/// Note: In R0.3.14 firmware the Device type string is no longer hardcoded to OMNI-01 in the firmware.
/// Now the Factory can program a different string based on if it is a T2 or R2 variant.
/// </para>
/// </summary>
public class VersionAndType : ASCIIString
{
const int LENGTH = 12;
public VersionAndType() : base(LENGTH)
{
}
public VersionAndType(byte[] response) : base(response, LENGTH)
{
}
}
}
@@ -0,0 +1,4 @@
namespace OmniPlus.Hanlers
{
internal delegate void DataReceivedHandler(byte[] bytes);
}
@@ -0,0 +1,4 @@
namespace OmniPlus.Hanlers
{
internal delegate void LogMessageEventHandler(string message);
}
@@ -0,0 +1,4 @@
namespace OmniPlus.Hanlers
{
internal delegate byte[] MessageHandler(params byte[] bytes);
}
@@ -0,0 +1,6 @@
using OmniPlus.Enums;
namespace OmniPlus.Hanlers
{
internal delegate void StateChangedEventHandler(SerialPortState state, string reason);
}
+105
View File
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F8D84B9A-0FCF-4083-B067-8C39B7314152}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OmniPlus</RootNamespace>
<AssemblyName>OmniPlus</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<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.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Connections\IrdaConnection.cs" />
<Compile Include="Enums\MessurementUnits.cs" />
<Compile Include="Enums\ReadingSettings.cs" />
<Compile Include="Enums\Status.cs" />
<Compile Include="Enums\TimeUnits.cs" />
<Compile Include="Features\ASCIIString.cs" />
<Compile Include="Features\BatteryVoltage.cs" />
<Compile Include="Features\BuildInfo.cs" />
<Compile Include="Features\ChamberCalibration.cs" />
<Compile Include="Features\ConfigurationParameters.cs" />
<Compile Include="Features\CustomerText.cs" />
<Compile Include="Features\DeviceID.cs" />
<Compile Include="Features\Epoch20000101.cs" />
<Compile Include="Features\FactoryID.cs" />
<Compile Include="Features\Features.cs" />
<Compile Include="Features\FeatureRequest.cs" />
<Compile Include="Features\FeatureResponse.cs" />
<Compile Include="Features\InputVolume.cs" />
<Compile Include="Features\ManifacturingTime.cs" />
<Compile Include="Features\OptionalUniDirFields.cs" />
<Compile Include="Features\ProgrammableID.cs" />
<Compile Include="Features\RateResolution.cs" />
<Compile Include="Features\RateUnits.cs" />
<Compile Include="Features\ReadingDigits.cs" />
<Compile Include="Features\ReadingMode.cs" />
<Compile Include="Features\ReadingPreset.cs" />
<Compile Include="Features\Readings.cs" />
<Compile Include="Features\ReadingResolution.cs" />
<Compile Include="Features\ReadingUnits.cs" />
<Compile Include="Features\RegisterSettings.cs" />
<Compile Include="Features\SystemParameters.cs" />
<Compile Include="Features\SystemTime.cs" />
<Compile Include="Features\VersionAndType.cs" />
<Compile Include="OmniPlusConnection.cs" />
<Compile Include="Connections\SerialPortConnection.cs" />
<Compile Include="Connections\UniProConnection.cs" />
<Compile Include="Enums\BaudRate.cs" />
<Compile Include="Enums\DataBits.cs" />
<Compile Include="Enums\SerialPortState.cs" />
<Compile Include="Hanlers\DataReceivedHandler.cs" />
<Compile Include="Hanlers\LogMessageHandler.cs" />
<Compile Include="Hanlers\MessageHandler.cs" />
<Compile Include="Hanlers\StateChangedHandler.cs" />
<Compile Include="OmniPlusConnectionsPool.cs" />
<Compile Include="OmniPlusDatabase.cs" />
<Compile Include="OmniPlusExtensions.cs" />
<Compile Include="OmniPlusInspectionHeaders.cs" />
<Compile Include="OmniPlusInspectionPoint.cs" />
<Compile Include="OmniPlusMeter.cs" />
<Compile Include="OmniPlusStateChangedEventHandler.cs" />
<Compile Include="Options\OmniControlOptions.cs" />
<Compile Include="Options\SerialPortOptions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NamedPipes\NamedPipes.csproj">
<Project>{0CC5A97F-E1CD-412B-AFFE-B256FDB7DC19}</Project>
<Name>NamedPipes</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+276
View File
@@ -0,0 +1,276 @@
using OmniPlus.Features;
using OmniPlus.Hanlers;
using System;
using static OmniPlus.Features.Features;
namespace OmniPlus.Connections
{
public class OmniPlusConnection
{
private readonly IrdaConnection irdaConnection;
private readonly UniProConnection uniProConnection;
public OmniPlusConnection(string portName)
{
this.irdaConnection = new IrdaConnection(portName);
this.uniProConnection = new UniProConnection(portName);
}
internal MessageHandler MessageHandler;
public bool ConnectIrda()
{
this.uniProConnection.Close();
this.irdaConnection.Open();
this.MessageHandler = this.irdaConnection.SendMessage;
return this.irdaConnection.Connected;
}
public bool ConnectUniPro()
{
this.irdaConnection.Close();
this.uniProConnection.Open();
this.MessageHandler = this.uniProConnection.SendMessage;
return this.irdaConnection.Connected;
}
public void Disconnect()
{
this.uniProConnection.Close();
this.irdaConnection.Close();
}
public FactoryID ViewFactoryID()
{
var response = this.MessageHandler.Invoke(VIEW_FACTORY_ID);
return new FactoryID(response);
}
public FeatureResponse SetFactoryID(FactoryID factoryID)
{
var response = this.MessageHandler.Invoke(factoryID[SET_FACTORY_ID]);
return new FeatureResponse(response);
}
public ProgrammableID ViewProgrammableID()
{
var response = this.MessageHandler.Invoke(VIEW_PROGRAMMABLE_ID);
return new ProgrammableID(response);
}
public FeatureResponse SetProgrammableID(ProgrammableID programmableID)
{
var response = this.MessageHandler.Invoke(programmableID[SET_PROGRAMMABLE_ID]);
return new FeatureResponse(response);
}
public VersionAndType ViewVersionAndType()
{
var response = this.MessageHandler.Invoke(VIEW_VERSION_AND_TYPE);
return new VersionAndType(response);
}
public CustomerText ViewCustomerText()
{
var response = this.MessageHandler.Invoke(VIEW_CUSTOMER_TEXT);
return new CustomerText(response);
}
public FeatureResponse SetCustomerText(CustomerText customerText)
{
var response = this.MessageHandler.Invoke(customerText[SET_CUSTOMER_TEXT]);
return new FeatureResponse(response);
}
public ReadingDigits ViewReadingDigits()
{
var response = this.MessageHandler.Invoke(VIEW_READING_DIGITS);
return new ReadingDigits(response);
}
public FeatureResponse SetReadingDigits(ReadingDigits readingDigits)
{
var response = this.MessageHandler.Invoke(readingDigits[SET_READING_DIGITS]);
return new FeatureResponse(response);
}
public ReadingUnits ViewReadingUnits()
{
var response = this.MessageHandler.Invoke(VIEW_READING_UNITS);
return new ReadingUnits(response);
}
public FeatureResponse SetReadingUnits(ReadingUnits readingUnits)
{
var response = this.MessageHandler.Invoke(readingUnits[SET_READING_UNITS]);
return new FeatureResponse(response);
}
public RateUnits ViewRateUnits()
{
var response = this.MessageHandler.Invoke(VIEW_RATE_UNITS);
return new RateUnits(response);
}
public FeatureResponse SetRateUnits(RateUnits rateUnits)
{
var response = this.MessageHandler.Invoke(rateUnits[SET_RATE_UNITS]);
return new FeatureResponse(response);
}
public ReadingResolution ViewReadingResolution()
{
var response = this.MessageHandler.Invoke(VIEW_READING_RESOLUTION);
return new ReadingResolution(response);
}
public FeatureResponse SetReadingResolution(ReadingResolution readingResolution)
{
var response = this.MessageHandler.Invoke(readingResolution[SET_READING_RESOLUTION]);
return new FeatureResponse(response);
}
public RateResolution ViewRateResolution()
{
var response = this.MessageHandler.Invoke(VIEW_RATE_RESOLUTION);
return new RateResolution(response);
}
public FeatureResponse SetRateResolution(RateResolution rateResolution)
{
var response = this.MessageHandler.Invoke(rateResolution[SET_READING_RESOLUTION]);
return new FeatureResponse(response);
}
public Readings ViewReadings(Readings reading)
{
var response = this.MessageHandler.Invoke(VIEW_READINGS);
return new Readings(response);
}
public FeatureResponse SetReadingPreset(ReadingPreset readingPreset)
{
var response = this.MessageHandler.Invoke(readingPreset[SET_READING_PRESET]);
return new FeatureResponse(response);
}
public ReadingMode ViewReadingMode()
{
var response = this.MessageHandler.Invoke(VIEW_READING_MODE);
return new ReadingMode(response);
}
public FeatureResponse SetReadingMode(ReadingMode readingMode)
{
var response = this.MessageHandler.Invoke(readingMode[SET_READING_MODE]);
return new FeatureResponse(response);
}
public BuildInfo ViewBuildInformation()
{
var response = this.MessageHandler.Invoke(VIEW_BUILD_INFORMATION);
return new BuildInfo(response);
}
public FeatureResponse SetBuildInformation(BuildInfo buildInformation)
{
var response = this.MessageHandler.Invoke(buildInformation[SET_BUILD_INFORMATION]);
return new FeatureResponse(response);
}
public SystemParameters ViewSystemParameters()
{
var response = this.MessageHandler.Invoke(DEVICE_SPECIFIC, VIEW_SYSTEM_PARAMETERS);
return new SystemParameters(response);
}
public ConfigurationParameters ViewConfigurationParameters()
{
var response = this.MessageHandler.Invoke(DEVICE_SPECIFIC, VIEW_CONFIGURATION_PARAMETERS, 0x01);
return new ConfigurationParameters(response);
}
public InputVolume SetInputVolume()
{
var response = this.MessageHandler.Invoke(DEVICE_SPECIFIC, VIEW_INPUT_VOLUME);
return new InputVolume(response);
}
public FeatureResponse SetInputVolume(InputVolume inputVolume)
{
var response = this.MessageHandler.Invoke(inputVolume[DEVICE_SPECIFIC, SET_INPUT_VOLUME]);
return new FeatureResponse(response);
}
public ChamberCalibration StartChamberCalibration(ushort rotations, ushort duration)
{
var response = this.MessageHandler.Invoke(new ChamberCalibration
{
Rotations = rotations,
Duration = duration,
Control = ChamberCalibration.ACTIVATE_TEST
});
return new ChamberCalibration(response);
}
public ChamberCalibration ViewChamberCalibration()
{
var response = this.MessageHandler.Invoke(DEVICE_SPECIFIC, CHAMBER_CALIBRATION, ChamberCalibration.REQUEST_RESULTS);
return new ChamberCalibration(response);
}
internal SystemTime ViewSystemTime()
{
var response = this.MessageHandler.Invoke(DEVICE_SPECIFIC, VIEW_SYSTEM_TIME);
return new SystemTime(response);
}
internal FeatureResponse SetSystemTime(SystemTime systemTime = null)
{
if (systemTime is null)
{
systemTime = new SystemTime();
}
var response = this.MessageHandler.Invoke(systemTime[DEVICE_SPECIFIC, SET_SYSTEM_TIME]);
return new FeatureResponse(response);
}
}
}
+351
View File
@@ -0,0 +1,351 @@
using NamedPipes;
using OmniPlus.Connections;
using OmniPlus.Features;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Threading.Tasks;
using static OmniPlus.UI.Inspection.OmniPlusInspectionHeaders;
namespace OmniPlus.UI.Inspection
{
public class OmniPlusConnectionsPool : IDisposable
{
public event OmniPlusStateChangedEventHandler StateChanged;
private readonly ConcurrentDictionary<int, OmniPlusConnection> connections;
private readonly ConcurrentDictionary<int, OmniPlusMeter> meters;
private readonly ConcurrentDictionary<int, Task> tasks;
private readonly NamedPipeClient namedPipeClient;
private readonly OmniPlusDatabase database;
private bool available;
private int size;
public OmniPlusConnectionsPool(string dbConnectionString)
{
this.connections = new ConcurrentDictionary<int, OmniPlusConnection>();
this.meters = new ConcurrentDictionary<int, OmniPlusMeter>();
this.namedPipeClient = new NamedPipeClient();
this.database = new OmniPlusDatabase(dbConnectionString);
}
public void Dispose()
{
if (this.StateChanged != null)
{
foreach (var callback in this.StateChanged.GetInvocationList())
{
if (callback is OmniPlusStateChangedEventHandler stateChangedCallback)
{
this.StateChanged -= stateChangedCallback;
}
}
}
foreach (var connection in this.connections.Values)
{
connection?.Disconnect();
}
this.namedPipeClient.Connected -= this.NamedPipeClient_Connected;
this.namedPipeClient.Disconnected -= this.NamedPipeClient_Disconnected;
this.namedPipeClient.Disconnect();
this.connections.Clear();
this.meters.Clear();
}
public void InitializeInspection(params string[] portNames)
{
this.namedPipeClient.Connected += this.NamedPipeClient_Connected;
this.namedPipeClient.Disconnected += this.NamedPipeClient_Disconnected;
this.namedPipeClient.Connect();
OmniPlusConnection connection;
OmniPlusMeter meter;
var connections = 0;
var position = 1;
foreach (var portName in portNames)
{
connection = new OmniPlusConnection(portName);
meter = new OmniPlusMeter();
if (connection.ConnectIrda())
{
meter.Connected = true;
connections++;
}
else
{
connection.Disconnect();
connection = default(OmniPlusConnection);
meter = default(OmniPlusMeter);
}
this.meters.TryAdd(position, meter);
this.connections.TryAdd(position, connection);
this.StateChanged?.Invoke(position, true, SLOT_NR, position.ToString());
position++;
}
if (this.available)
{
this.available = connections > 0;
}
}
public void StartInspection()
{
this.StartOmniInitialization();
this.StartOmniCalibration();
this.FinishOmniInspection();
}
private void StartOmniInitialization()
{
var factory = Task.Factory;
foreach (var position in this.connections.Keys)
{
this.tasks[position] = factory.StartNew(() => this.StartOmniInitialization(position));
}
factory.ContinueWhenAll(this.tasks.Values.ToArray(), _ => { });
}
private void StartOmniInitialization(int position)
{
if (this.TryGetOmni(position, out var connection, out var meter))
{
this.StateChanged?.Invoke(position, meter.Connected, CONNECTED, meter.Connected ? OK : X);
var systemParameters = connection.ViewSystemParameters();
meter.Initialized = systemParameters.Succeeded;
meter.AddSystemParameters(systemParameters);
this.database.AddOrUpdate(systemParameters);
this.StateChanged?.Invoke(position, meter.FirmwareInRange, FIRMWARE, meter.Firmware);
this.StateChanged?.Invoke(position, true, BUILD_INFO, meter.BuildInfo);
this.StateChanged?.Invoke(position, meter.ManifacturingTimeInRange, CREATED_ON, $"{meter.ManifacturingTime:yyyy-MM-dd}");
this.StateChanged?.Invoke(position, meter.SystemTimeInRange, LAST_UPDATE, $"{meter.SystemTimeDrift} Sek.");
this.StateChanged?.Invoke(position, meter.RebootsCount != 0xFF, REBOOTS_CNT, meter.RebootsCount.ToString());
this.StateChanged?.Invoke(position, !meter.FactorySealed, SEALED, !meter.FactorySealed ? X : OK);
if (meter.Initialized)
{
var inputVolume = this.database.GetInputVolume(meter.Size);
var inputVolumResponse = connection.SetInputVolume(inputVolume);
meter.Initialized = inputVolumResponse.Succeeded;
if (meter.Initialized)
{
meter.AddInputVolume(inputVolume);
}
}
this.StateChanged?.Invoke(position, meter.Initialized, ML_PER_PULSE, $"{meter.MlPerPulse:0.00000}");
}
else // meter or connection not in use
{
this.StateChanged?.Invoke(position, null, CONNECTED, null);
this.StateChanged?.Invoke(position, null, FIRMWARE, null);
this.StateChanged?.Invoke(position, null, BUILD_INFO, null);
this.StateChanged?.Invoke(position, null, CREATED_ON, null);
this.StateChanged?.Invoke(position, null, LAST_UPDATE, null);
this.StateChanged?.Invoke(position, null, REBOOTS_CNT, null);
this.StateChanged?.Invoke(position, null, SEALED, null);
this.StateChanged?.Invoke(position, null, ML_PER_PULSE, null);
}
}
private void StartOmniCalibration()
{
var factory = Task.Factory;
var inspectionPoints = this.database.GetInspectionPoints(this.size);
foreach (var point in inspectionPoints)
{
this.namedPipeClient.RequestFlowRate(point.FlowRate);
foreach (var position in this.connections.Keys)
{
this.tasks[position] = factory.StartNew(() => this.StartOmniCalibration(position, point));
}
factory.ContinueWhenAll(this.tasks.Values.ToArray(), _ => { });
var volume = this.namedPipeClient.RequestReference();
foreach (var meter in this.meters.Values)
{
meter.AddInspectionVolume(point, volume);
}
}
foreach(var position in this.connections.Keys)
{
this.tasks[position] = factory.StartNew(() => this.CalibrateMeter(position));
}
factory.ContinueWhenAll(this.tasks.Values.ToArray(), _ => { });
}
private void StartOmniCalibration(int position, OmniPlusInspectionPoint point)
{
var header = $"{point.Rotations}/{point.Seconds}R/Sek.";
var progress = 0;
this.StateChanged?.Invoke(position, null, header, $"{progress}%");
if (this.TryGetOmni(position, out var connection, out var meter))
{
if (!meter.CanCalibrate)
{
this.StateChanged?.Invoke(position, false, header, X);
return;
}
var activationResponse = connection.StartChamberCalibration(point.Rotations, point.Seconds);
var calibrationResult = default(ChamberCalibration);
if (activationResponse.Succeeded)
{
progress += 10;
this.StateChanged?.Invoke(position, true, header, $"{progress}%");
//0x00 indicates that the parameters are valid and test will start 3 seconds after the response.
Thread.Sleep(3000);
progress += 10;
this.StateChanged?.Invoke(position, true, header, $"{progress}%");
// waiting all the secconds to execute test
Thread.Sleep(point.Seconds * 1000);
progress += 70;
this.StateChanged?.Invoke(position, true, header, $"{progress}%");
var delay = (int)(point.Seconds * 0.1) * 1000;
for (int i = 0; i < 3; i++)
{
calibrationResult = connection.ViewChamberCalibration();
if (calibrationResult.Succeeded)
{
break;
}
Thread.Sleep(delay);
progress += 3;
this.StateChanged?.Invoke(position, true, header, $"{progress}%");
}
if (calibrationResult?.Succeeded == true)
{
if (calibrationResult.Control == ChamberCalibration.TEST_COMPLETED)
{
this.StateChanged?.Invoke(position, true, header, $"100%");
}
else // calibration timeout or not ready but exceeds the 3s + seconds to run + 0.3%
{
this.StateChanged?.Invoke(position, false, header, X);
}
}
else // calibration failed
{
this.StateChanged?.Invoke(position, false, header, "n/a");
}
}
else // activation failed
{
this.StateChanged?.Invoke(position, false, header, "n/a");
}
meter.AddCalibrationResult(point, calibrationResult);
}
else // meter or connection not in use
{
this.StateChanged?.Invoke(position, null, header, null);
}
}
private void CalibrateMeter(int position)
{
if (this.TryGetOmni(position, out var connection, out var meter))
{
var correctionFactor = meter.CalculateCorrectionFactor();
this.StateChanged?.Invoke(position, meter.Calibrated, CORRECTION, $"{correctionFactor:0.00}%");
}
else // meter or connection not in use
{
this.StateChanged?.Invoke(position, null, CORRECTION, null);
}
}
private void FinishOmniInspection()
{
var factory = Task.Factory;
foreach (var position in this.connections.Keys)
{
this.tasks[position] = factory.StartNew(() => this.FinishOmniInspection(position));
}
}
private void FinishOmniInspection(int position)
{
if (this.TryGetOmni(position, out var connection, out var meter))
{
var configurationParameters = connection.ViewConfigurationParameters();
var canContinue = configurationParameters.Succeeded;
if (canContinue)
{
var systemTimeReset = connection.SetSystemTime();
canContinue = systemTimeReset.Succeeded;
}
if (canContinue)
{
var registerSettings = connection.ViewRegisterSettings();
}
}
else // meter or connection not in use
{
}
}
private bool TryGetOmni(int position, out OmniPlusConnection connection, out OmniPlusMeter meter)
{
var connectionFound = this.connections.TryGetValue(position, out connection);
var meterFound = this.meters.TryGetValue(position, out meter);
return connectionFound
&& connection != null
&& meterFound
&& meter != null
&& meter.Connected;
}
private void NamedPipeClient_Connected()
=> this.available = true;
private void NamedPipeClient_Disconnected()
=> this.available = false;
}
}
+30
View File
@@ -0,0 +1,30 @@
using OmniPlus.Features;
using System;
using System.Collections.Generic;
namespace OmniPlus.UI.Inspection
{
internal class OmniPlusDatabase
{
private readonly string connectionString;
public OmniPlusDatabase(string omniDatabase)
=> this.connectionString = omniDatabase;
internal void AddOrUpdate(SystemParameters systemParameters)
{
}
internal InputVolume GetInputVolume(object size)
{
return new InputVolume();
}
internal IEnumerable<OmniPlusInspectionPoint> GetInspectionPoints(int size)
{
return new OmniPlusInspectionPoint[] { };
}
}
}
+275
View File
@@ -0,0 +1,275 @@
using OmniPlus.Options;
using System;
namespace OmniPlus
{
internal static class OmniPlusExtensions
{
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_MIN_LENGTH = 5;
public const byte UI1236_HED_LENGTH = 3;
public const byte IRDA_START = 0x9B;
public const byte IRDA_PC2REG = 0x33;
public const byte IRDA_REG2PC = 0x43;
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 bytesLength = bytes.Length;
var payloadLength = bytes.Length + UI1236_MIN_LENGTH;
payloadLength += payloadLength % OxO2;
var index = OxOO;
var message = new byte[payloadLength];
message[index++] = UI1236_START;
message[index++] = (byte)(bytesLength + UI1236_HED_LENGTH);
OmniControlOptions control = OxOO;
control.ReturnResponse = true;
message[index++] = control;
bytes.CopyTo(message, index--);
var checksum = message.CalculateCheckSUM(message.Length - OxO2);
var checksumIndex = bytesLength + UI1236_HED_LENGTH;
message[checksumIndex++] = checksum[OxO1];
message[checksumIndex++] = checksum[OxOO];
return message;
}
/// <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[] FromUI1236Message(this byte[] bytes)
{
var payload = new byte[OxOO];
if (bytes is null)
{
return payload;
}
var payloadLength = bytes.Length - UI1236_MIN_LENGTH;
if (payloadLength <= OxOO)
{
return payload;
}
payload = new byte[payloadLength];
Array.Copy(bytes, OxO3, payload, OxOO, payloadLength);
return payload;
}
/// <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 byte[] FromUniProMessage(this byte[] bytes)
{
var payload = new byte[OxOO];
if (bytes is null)
{
return payload;
}
var payloadLength = bytes.Length - UNIPRO_MIN_LENGTH;
if (payloadLength <= OxOO)
{
return payload;
}
payload = new byte[payloadLength];
Array.Copy(bytes, OxO3, payload, OxOO, payloadLength);
return payload;
}
/// <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 payloadLength = bytes.Length;
payloadLength += payloadLength % OxO2;
var index = OxOO;
var message = new byte[payloadLength + IRDA_MIN_LENGTH];
message[index++] = IRDA_START;
message[index++] = IRDA_PC2REG;
message[index++] = (byte)(payloadLength / OxO2);
bytes.CopyTo(message, index);
var messageLength = message.Length;
var crc16 = message.CalculateCRC8408(1, messageLength - IRDA_CRC_LENGTH);
message[messageLength - OxO2] = crc16[OxOO];
message[messageLength - 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 byte[] FromIrdaMessage(this byte[] bytes)
{
var payload = new byte[OxOO];
if (bytes is null)
{
return payload;
}
var payloadLength = bytes.Length - IRDA_MIN_LENGTH;
if (payloadLength <= OxOO)
{
return payload;
}
payload = new byte[payloadLength];
Array.Copy(bytes, OxO3, payload, OxOO, payloadLength);
return payload;
}
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 void Clear(this byte[] bytes)
{
var length = bytes.Length;
for (int i = OxOO; i < length; i++)
{
bytes[i] = OxOO;
}
}
public static string ToASCIIString(this byte[] bytes, int start, int end)
{
var asciiString = string.Empty;
while (start <= end)
{
asciiString += (char)bytes[start];
start++;
}
return asciiString.Trim();
}
}
}
@@ -0,0 +1,23 @@
namespace OmniPlus.UI.Inspection
{
internal class OmniPlusInspectionHeaders
{
public const string COMS_CONFIG = "COMS";
public const string SLOT_NR = "Einbauplatz";
public const string CONNECTED = "Verbunden";
public const string FIRMWARE = "Firmware";
public const string CREATED_ON = "Herstellungsdatum";
public const string LAST_UPDATE = "Letzte Aktualisierung";
public const string REBOOTS_CNT = "Neustarts";
public const string SEALED = "Versiegelt";
public const string BUILD_INFO = "Build-Info";
public const string ML_PER_PULSE = "ml/Puls";
public const string CORRECTION = "Korrekturfaktor";
//public const string REBOOTS_CNT = "Neustarts";
//public const string REBOOTS_CNT = "Neustarts";
public const string OK = "✓";
public const string X = "✘";
}
}
@@ -0,0 +1,16 @@
namespace OmniPlus.UI.Inspection
{
using System;
internal struct OmniPlusInspectionPoint : IComparable<OmniPlusInspectionPoint>
{
public double FlowRate { get; set; }
public ushort Rotations { get; set; }
public ushort Seconds { get; set; }
public int CompareTo(OmniPlusInspectionPoint other)
=> this.Rotations.CompareTo(other.Rotations);
}
}
+174
View File
@@ -0,0 +1,174 @@
using OmniPlus.Features;
using System;
using System.Collections.Generic;
namespace OmniPlus.UI.Inspection
{
internal class OmniPlusMeter
{
private readonly IDictionary<OmniPlusInspectionPoint, double> inspectionPoints;
private readonly IDictionary<OmniPlusInspectionPoint, ChamberCalibration> calibrationResults;
private InputVolume inputVolume;
private SystemParameters systemParameters;
public OmniPlusMeter(bool connected = false)
{
this.Connected = connected;
this.inputVolume = new InputVolume();
this.systemParameters = new SystemParameters();
this.inspectionPoints = new Dictionary<OmniPlusInspectionPoint, double>();
this.calibrationResults = new Dictionary<OmniPlusInspectionPoint, ChamberCalibration>();
}
public bool Connected { get; set; }
public bool Initialized { get; set; }
public bool CanCalibrate { get; set; } = true;
public bool Calibrated { get; private set; }
public byte Size
{
get => this.inputVolume.Size;
set => this.inputVolume.Size = value;
}
public byte Range
{
get => this.inputVolume.Range;
set => this.inputVolume.Range = value;
}
public ushort IntPart
{
get => this.inputVolume.IntPart;
set => this.inputVolume.IntPart = value;
}
public ushort Fraction
{
get => this.inputVolume.Fraction;
set => this.inputVolume.Fraction = value;
}
public string BuildInfo
{
get => this.systemParameters.BuildInfo.Value.Trim('\0');
set => this.systemParameters.BuildInfo.Value = value;
}
public DateTime ManifacturingTime
{
get => this.systemParameters.ManifacturingTime.DateTime;
set => this.systemParameters.ManifacturingTime.DateTime = value;
}
public bool ManifacturingTimeInRange { get; private set; }
public DateTime SystemTime
{
get => this.systemParameters.SystemTime.DateTime;
set => this.systemParameters.SystemTime.DateTime = value;
}
public int SystemTimeDrift { get; private set; }
public bool SystemTimeInRange { get; private set; }
public byte RebootsCount
{
get => this.systemParameters.RebootsCount;
set => this.systemParameters.RebootsCount = value;
}
public string Firmware
{
get => this.systemParameters.VersionAndType.Value.Trim('\0');
set => this.systemParameters.VersionAndType.Value = value;
}
public bool FirmwareInRange { get; private set; }
public double Volts
{
get => Math.Max(this.systemParameters.BatteryVoltage.Volts, (ushort)1) / 1000.0;
set => this.systemParameters.BatteryVoltage.Volts = (ushort)(value * 1000);
}
public bool VoltsInRange => 3.19 <= this.Volts && this.Volts <= 3.75;
public uint ADCCounts
{
get => this.systemParameters.BatteryVoltage.ADCCount;
set => this.systemParameters.BatteryVoltage.ADCCount = value;
}
public bool FactorySealed
{
get => this.systemParameters.FactorySealed;
set => this.systemParameters.FactorySealed = value;
}
public double MlPerPulse { get; private set; }
internal void AddInputVolume(InputVolume inputVolume)
{
if (inputVolume != null)
{
this.inputVolume = inputVolume;
if (this.inputVolume.Fraction > 0)
{
this.MlPerPulse = this.inputVolume.Fraction / ushort.MaxValue * this.inputVolume.Factor;
}
}
}
internal void AddSystemParameters(SystemParameters systemParameters)
{
if (systemParameters != null)
{
this.systemParameters = systemParameters;
this.SystemTimeDrift = (DateTime.UtcNow - this.SystemTime).Seconds;
this.SystemTimeInRange = Math.Abs(this.SystemTimeDrift) <= 700;
this.ManifacturingTimeInRange = Math.Abs((DateTime.UtcNow - this.ManifacturingTime).Days) <= 365;
var firmwareTokens = this.Firmware
?.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
?? new string[2];
var versionString = firmwareTokens[0]?.Substring(1) ?? string.Empty;
var versionParsed = double.TryParse(versionString, out var version);
var typeString = firmwareTokens[1]?.ToUpper() ?? string.Empty;
var isOmni = typeString == "OMNI-1" || typeString == "OMNI-2";
this.FirmwareInRange = versionParsed && version >= 1.23 && isOmni;
}
}
internal void AddCalibrationResult(OmniPlusInspectionPoint point, ChamberCalibration result)
{
this.calibrationResults[point] = result;
if (this.CanCalibrate)
{
this.CanCalibrate
= result != null
&& result.Succeeded
&& result.Control == ChamberCalibration.TEST_COMPLETED;
}
}
internal void AddInspectionVolume(OmniPlusInspectionPoint point, double volume)
=> this.inspectionPoints[point] = volume;
internal double CalculateCorrectionFactor()
{
// TODO: calculate correction factor.
return double.MinValue;
}
}
}
@@ -0,0 +1,4 @@
namespace OmniPlus.UI.Inspection
{
public delegate void OmniPlusStateChangedEventHandler(int column, bool? succeeded, string header, string value);
}
@@ -0,0 +1,66 @@
namespace OmniPlus.Options
{
internal class OmniControlOptions
{
private readonly byte[] bits;
private OmniControlOptions(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 OmniControlOptions(byte controlByte)
{
var bits = new byte[8];
for (int i = 0; i < 8; i++)
{
bits[i] = (byte)((controlByte >> i) & 1);
}
return new OmniControlOptions(bits);
}
public static implicit operator byte (OmniControlOptions control)
{
var @byte = default(byte);
for (int i = 0; i < 8; i++)
{
@byte ^= (byte)(control.bits[i] << i);
}
return @byte;
}
}
}
@@ -0,0 +1,36 @@
using OmniPlus.Enums;
using System.IO.Ports;
namespace OmniPlus.Options
{
public class SerialPortOptions
{
public SerialPortOptions()
{
this.BaudRate = BaudRate.K4800;
this.DataBits = DataBits.X8;
this.Parity = Parity.None;
this.StopBits = StopBits.One;
this.Handshake = Handshake.None;
}
public string PortName { get; set; }
public BaudRate BaudRate { get; set; }
public Parity Parity { get; set; }
public DataBits DataBits { get; set; }
public StopBits StopBits { get; set; }
public Handshake Handshake { get; set; }
public bool RtsEnabled { get; set; }
public bool DtrEnabled { get; set; }
public string LogFile { get; set; }
}
}
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
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("OmniPlus")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OmniPlus")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[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)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f8d84b9a-0fcf-4083-b067-8c39b7314152")]
// 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")]
@@ -1,14 +0,0 @@
namespace SIRTBroadcaster.Abstraction
{
/// <summary>
/// Sends <see cref="SIRTMessage"/>.
/// </summary>
public interface IMessageSender
{
/// <summary>
/// Sends <see cref="SIRTMessage"/>.
/// </summary>
/// <param name="message"> - to send.</param>
void SendMessage(SIRTMessage message);
}
}
@@ -1,16 +0,0 @@
namespace SIRTBroadcaster.Abstraction
{
using System;
/// <summary>
/// This interface holds the shared endpoints iplemented as well in the SignalR Hubs as in the clients.
/// </summary>
public interface ISIRTBroadcaster : IMessageSender, IDisposable
{
/// <summary>
/// Receives <see cref="SIRTMessage"/>.
/// </summary>
/// <param name="message">- to receive.</param>
void MessageReceived(SIRTMessage message);
}
}
@@ -1,12 +0,0 @@
namespace SIRTBroadcaster.Abstraction
{
using System;
/// <summary>
/// TODO: Add description ...
/// </summary>
public interface ISIRTBroadcasterClient : IMessageSender, IDisposable
{
event Action<uint> UnitDetected;
}
}
@@ -1,12 +0,0 @@
namespace SIRTBroadcaster.Abstraction
{
using System;
/// <summary>
/// SIRT broadcaster host interface.
/// </summary>
public interface ISIRTBroadcasterHost : IMessageSender, IDisposable
{
}
}
@@ -1,12 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("SIRTBroadcaster.Abstraction")]
[assembly: AssemblyDescription("Shared library between SignalR hubs and desktop clients.")]
[assembly: AssemblyCompany("SENSUS - a Xylem brand.")]
[assembly: AssemblyProduct("SIRTBroadcaster.Abstraction")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: ComVisible(false)]
[assembly: Guid("c27ba66c-c3a7-48a2-a644-cba77e28e531")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -1,16 +0,0 @@
namespace SIRTBroadcaster.Abstraction
{
public class SIRTConnection : SIRTModel
{
public string SirtPort { get; set; }
public override bool Equals(object other)
=> other?.GetHashCode() == this.GetHashCode();
public override int GetHashCode()
=> this.SirtId?.GetHashCode() ?? 0;
public override string ToString()
=> this.SirtId;
}
}
@@ -1,111 +0,0 @@
namespace SIRTBroadcaster.Abstraction
{
using System;
using System.Linq;
/// <summary>
/// TODO: Add description ...
/// </summary>
public static class SIRTExtensions
{
public static byte[] ToByteArray(this SIRTMessage message)
{
var length = 12 + message.DataLength;
var bytes = new byte[length];
bytes[0] = message.StartByte;
bytes[1] = message.MessageType;
bytes[2] = message.Parameter1;
bytes[3] = message.Parameter2;
/// TODO: see if radio address is correct hinzugefügt.
/// Copying address bytes to the message bytes.
/// Index 4 <=> 7.
BitConverter
.GetBytes(message.Address)
.Reverse()
.ToArray()
.CopyTo(bytes, 4);
bytes[8] = message.DataLength;
/// Copying data bytes to the message bytes.
/// Index 9 <=> <see cref="SIRTMessage.DataLength"/>.
message.Data.CopyTo(bytes, 9);
/// TODO: see if CRC is correct hinzugefügt.
bytes
.CalculateCRC(1, (ushort)(length - 4))
.Reverse()
.ToArray()
.CopyTo(bytes, length - 3);
bytes[length - 1] = message.StopByte;
return bytes;
}
public static byte[] CalculateCRC(this byte[] data, ushort start, ushort length)
{
var ui_index = start;
var test = default(byte);
var zeichen = default(byte);
var crc_result = ushort.MaxValue;
if (data.Length >= length + start)
{
while (ui_index < length + start)
{
zeichen = 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 (((zeichen & 0x80) ^ test) != 0)
{
crc_result ^= 0x1021;
}
zeichen <<= 1;
}
}
}
return BitConverter.GetBytes(crc_result);
}
public static ushort ToUInt16(this byte[] data, int startIndex)
{
return BitConverter.ToUInt16(new byte[]
{
data[startIndex + 1],
data[startIndex],
}, 0);
}
public static uint ToUInt32(this byte[] data, int startIndex, bool reverced = true)
{
if (reverced)
{
return BitConverter.ToUInt32(new byte[]
{
data[startIndex + 3],
data[startIndex + 2],
data[startIndex + 1],
data[startIndex],
}, 0);
}
return BitConverter.ToUInt32(data, startIndex);
}
}
}
@@ -1,45 +0,0 @@
namespace SIRTBroadcaster.Abstraction
{
/// <summary>
/// Constant variables used in both SignalR and desctop clients.
/// </summary>
public class SIRTFixed
{
/// <summary>
/// Used for naming the SignalR hub as well as for building IHubProxy for the desctop clients.
/// </summary>
public const string SIRT_HUB = "SIRTBroadcaster";
public const string SIRT_URL = "http://sla12iis01.emea.sensus.net/LaaProductionWeb"; // "http://localhost:52822/";
public const byte FromAir = 0x11;
public const byte LastCMD = 0x12;
public const byte Debug = 0x14;
public const byte StopByte = 0x16;
public const byte StartSIRT2PC = 0xFF;
public const byte StartPC2SIRT = 0x55;
public const byte WritePAM = 0x81;
public const byte ReadPAM = 0x82;
public const byte WriteRegister = 0x84;
public const byte ReadRegister = 0x87;
public const byte WriteRAC = 0x88;
public const byte ReadRAC = 0x8B;
public const byte AddressLength = 4;
public const byte CRCLength = 2;
public const byte OxOO = 0x00;
}
}
@@ -1,91 +0,0 @@
namespace SIRTBroadcaster.Abstraction
{
using System;
/// <summary>
/// Generic SIRT message.
/// Keeped simple in order to be serialized (to) and deserialized (from) as JSON or other formats.
/// <list type="number">
/// <listheader>It has always the same structure:</listheader>
/// <item>[0] - Start byte.</item>
/// <item>[1] - Message type.</item>
/// <item>[2] - Parameter 1.</item>
/// <item>[3] - Parameter 2.</item>
/// <item>[4 .. 7] - Radio address.</item>
/// <item>[8] - Data length.</item>
/// <item>[9 .. n] - Data bytes.</item>
/// <item>[9 + n .. 9 + n + 2] - CRC check sum.</item>
/// <item>[9 + n + 3] - Stop byte.</item>
/// </list>
/// </summary>
public class SIRTMessage : SIRTModel
{
/// <summary>
/// <list type="bullet">
/// <listheader>Describes the message direction:</listheader>
/// <item>PC -> SIRT always = 0x55.</item>
/// <item>SIRT -> PC always = 0xFF.</item>
/// </list>
/// </summary>
public byte StartByte { get; set; }
/// <summary>
/// <list type="bullet">
/// <listheader>Describes the message type:</listheader>
/// <item>Write PAM = 0x81.</item>
/// <item>Read PAM = 0x82.</item>
/// <item>Write RAC = 0x88.</item>
/// <item>Read RAC = 0x8B.</item>
/// <item>Write SIRT = 0x84.</item>
/// <item>Read SIRT = 0x87.</item>
/// </list>
/// </summary>
public byte MessageType { get; set; }
/// <summary>
/// TODO: Add description ...
/// </summary>
public byte Parameter1 { get; set; }
/// <summary>
/// TODO: Add description ...
/// </summary>
public byte Parameter2 { get; set; }
/// <summary>
/// The radio address as Uint32 converted as follows:
/// <para />
/// <code>uint address = BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x00, 0x20 }, 0); // => 536870912.</code>
/// <para />
/// <code>byte[] addressBytes = BitConverter.GetBytes(address); // => new byte[] { 0x00, 0x00, 0x00, 0x20 }.</code>
/// <para>Note: From and to SIRT address bytes are reversed and are looking like that - new byte[] { 0x20, 0x00, 0x00, 0x00 }</para>
/// </summary>
public uint Address { get; set; }
/// <summary>
/// The length of the following data bytes.
/// Not longer than 128.
/// </summary>
public byte DataLength { get; set; }
/// <summary>
/// TODO: Add description ...
/// </summary>
public byte[] Data { get; set; } = new byte[0];
/// <summary>
/// TODO: Add description ...
/// </summary>
public byte[] CRC { get; set; } = new byte[2];
/// <summary>
/// TODO: Add description ...
/// </summary>
public byte StopByte { get; set; } = SIRTFixed.StopByte;
/// <summary>
/// TODO: Add description ...
/// </summary>
public DateTime TimeStamp { get; set; } = DateTime.Now;
}
}
@@ -1,9 +0,0 @@
namespace SIRTBroadcaster.Abstraction
{
public class SIRTModel
{
public string SirtId { get; set; }
public short SirtRF { get; set; }
}
}
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net481" />
</packages>
@@ -1,17 +0,0 @@
namespace SIRTBroadcaster.Client.Messages.FromAir
{
public class BUP
{
public byte AppCode { get; set; }
public byte Counter { get; set; }
public uint Address { get; set; }
public uint BillingVolume { get; set; }
public byte Alarm { get; set; }
public ushort CRC { get; set; }
}
}
@@ -1,69 +0,0 @@
namespace SIRTBroadcaster.Client.Messages.FromAir
{
public class DEBUG
{
public byte Length { get; set; }
public byte AppCode { get; set; }
public byte Counter { get; set; }
public uint Address { get; set; }
public byte DebugType { get; set; }
public byte MeterType { get; set; }
public byte VersionRadioFW { get; set; }
public byte VersionFW { get; set; }
public ushort RevisionFW { get; set; }
public byte VersionHW { get; set; }
public byte FactoryState { get; set; }
public uint PcbId { get; set; }
public byte Temperatur { get; set; }
public ushort BatteryV { get; set; }
public byte WakeUpInterval { get; set; }
public byte TXPowerRF { get; set; }
public byte TXPowerFlex { get; set; }
public ushort OffsetRF { get; set; }
public byte RebootCount { get; set; }
public byte WatchdogCount { get; set; }
public uint BatterySeconds { get; set; }
public byte MeterSampleRate { get; set; }
public byte HistoryScale { get; set; }
public byte RegisterMode { get; set; }
public byte HistorySize { get; set; }
public byte FactoryCalibration { get; set; }
public byte MeterSize { get; set; }
public uint VolumeLED { get; set; }
public uint Volume { get; set; }
public uint OffsetFactor { get; set; }
public byte OffsetTime { get; set; }
public ushort CRC { get; set; }
}
}
@@ -1,99 +0,0 @@
namespace SIRTBroadcaster.Client.Messages.FromAir
{
public class SEMI
{
public byte Length { get; set; }
public byte AppCode { get; set; }
public byte Counter { get; set; }
public uint Address { get; set; }
public uint BillingVolume { get; set; }
public byte Alarm { get; set; }
public byte PamStatus { get; set; }
public byte PamRSSI { get; set; }
public byte MeterType { get; set; }
public ushort TransmissionInterval { get; set; }
public byte LatInterval { get; set; }
public ushort CurrentFlow { get; set; }
public uint BackwardVolume { get; set; }
public byte NumberOfDials { get; set; }
public byte VolumUnit { get; set; }
public uint MeterId { get; set; }
public byte OMStatus { get; set; }
public ushort OMTransmissionInterval { get; set; }
public byte AlarmMaskActiveInfo { get; set; }
public byte LeakageDetectionParams { get; set; }
public byte BrokenPipeDetectionParams { get; set; }
public ushort BatteryRemaining { get; set; }
public ushort BatteryEndDetected { get; set; }
public ushort MaxFlow { get; set; }
public ushort MaxFlowTime { get; set; }
public ushort LowBatteryDetected { get; set; }
public ushort LeakStart { get; set; }
public ushort LeakEnd { get; set; }
public ushort MagneticTamperStart { get; set; }
public ushort MagneticTamperEnd { get; set; }
public ushort ModuleRemoveStart { get; set; }
public ushort ModuleRemoveEnd { get; set; }
public ushort BackflowStart { get; set; }
public ushort BackflowEnd { get; set; }
public ushort BrokenPipeStart { get; set; }
public ushort BrokenPipeEnd { get; set; }
public ushort LogContent { get; set; }
public ushort LoggingInterval { get; set; }
public ushort FixedDateReadingContent { get; set; }
public byte BillingDay { get; set; }
public uint ActualDateTime { get; set; }
public byte HistoryErrorLimitInDays { get; set; }
public string CustomerText { get; set; }
public ushort TimeOfFDRReset { get; set; }
public ushort TimeOfLogReset { get; set; }
public byte MeterSize { get; set; }
public ushort CRC { get; set; }
}
}
@@ -1,175 +0,0 @@
namespace SIRTBroadcaster.Client
{
using SIRTBroadcaster.Abstraction;
using SIRTBroadcaster.Client.Messages.FromAir;
using System;
using System.Collections.Concurrent;
using System.Text;
public partial class Payload
{
private readonly ConcurrentStack<BUP> bups;
private readonly ConcurrentStack<DEBUG> debugs;
private readonly ConcurrentStack<SEMI> semis;
private readonly string sirtId;
private readonly uint address;
public Payload(string sirtId, uint address)
{
this.sirtId = sirtId;
this.address = address;
this.bups = new ConcurrentStack<BUP>();
this.debugs = new ConcurrentStack<DEBUG>();
this.semis = new ConcurrentStack<SEMI>();
}
public event Action<BUP> NewBUP;
public event Action<DEBUG> NewDEBUG;
public event Action<SEMI> NewSEMI;
public BUP LastBUP => this.bups.TryPeek(out var bup) ? bup : new BUP();
public DEBUG LastDEBUG => this.debugs.TryPeek(out var debug) ? debug : new DEBUG();
public SEMI LastSEMI => this.semis.TryPeek(out var semi) ? semi : new SEMI();
internal void AddBUP(SIRTMessage message)
{
var data = message.Data;
var bup = new BUP
{
AppCode = data[0],
Counter = data[1],
Address = data.ToUInt32(2),
BillingVolume = data.ToUInt32(6),
Alarm = data[10],
CRC = data.ToUInt16(11),
};
this.bups.Push(bup);
this.NewBUP?.Invoke(bup);
}
internal void AddDEBUG(SIRTMessage message)
{
var data = message.Data;
var debug = new DEBUG
{
Length = data[0],
AppCode = data[1],
Counter = data[2],
Address = data.ToUInt32(3),
DebugType = data[7],
MeterType = data[8],
VersionRadioFW = data[9],
VersionFW = data[10],
RevisionFW = data.ToUInt16(11),
VersionHW = data[13],
FactoryState = data[14],
PcbId = data.ToUInt32(15),
Temperatur = data[19],
BatteryV = data.ToUInt16(20),
WakeUpInterval = data[22],
TXPowerRF = data[23],
TXPowerFlex = data[24],
OffsetRF = data.ToUInt16(25),
RebootCount = data[27],
WatchdogCount = data[28],
BatterySeconds = data.ToUInt32(29),
MeterSampleRate = data[33],
HistoryScale = data[34],
RegisterMode = data[35],
HistorySize = data[36],
FactoryCalibration = data[37],
MeterSize = data[38],
VolumeLED = data.ToUInt32(39),
Volume = data.ToUInt32(43),
OffsetFactor = data.ToUInt32(47),
OffsetTime = data[51]
};
if (data.Length == 53)
{
debug.CRC = data.ToUInt16(52);
}
this.debugs.Push(debug);
this.NewDEBUG?.Invoke(debug);
}
internal void AddSEMI(SIRTMessage message)
{
var data = message.Data;
var semi = new SEMI
{
Length = data[0],
AppCode = data[1],
Counter = data[2],
Address = data.ToUInt32(3),
BillingVolume = data.ToUInt32(7),
Alarm = data[11],
PamStatus = data[12],
PamRSSI = data[13],
MeterType = data[14],
TransmissionInterval = data.ToUInt16(15),
LatInterval = data[17],
CurrentFlow = data.ToUInt16(18),
BackwardVolume = data.ToUInt32(20),
NumberOfDials = data[24],
VolumUnit = data[25],
MeterId = data.ToUInt32(26),
OMStatus = data[30],
OMTransmissionInterval = data.ToUInt16(31),
AlarmMaskActiveInfo = data[33],
LeakageDetectionParams = data[34],
BrokenPipeDetectionParams = data[35],
BatteryRemaining = data.ToUInt16(36),
BatteryEndDetected = data.ToUInt16(38),
MaxFlow = data.ToUInt16(40),
MaxFlowTime = data.ToUInt16(42),
LowBatteryDetected = data.ToUInt16(44),
LeakStart = data.ToUInt16(46),
LeakEnd = data.ToUInt16(48),
MagneticTamperStart = data.ToUInt16(50),
MagneticTamperEnd = data.ToUInt16(52),
ModuleRemoveStart = data.ToUInt16(54),
ModuleRemoveEnd = data.ToUInt16(56),
BackflowStart = data.ToUInt16(58),
BackflowEnd = data.ToUInt16(60),
BrokenPipeStart = data.ToUInt16(62),
BrokenPipeEnd = data.ToUInt16(64),
LogContent = data.ToUInt16(66),
LoggingInterval = data.ToUInt16(68),
FixedDateReadingContent = data.ToUInt16(70),
BillingDay = data[72],
ActualDateTime = data.ToUInt32(73),
HistoryErrorLimitInDays = data[77],
CustomerText = Encoding.UTF8.GetString(new byte[]
{
data[78],
data[79],
data[80],
data[81],
data[82],
data[83],
data[84],
data[85],
data[86],
}),
TimeOfFDRReset = data.ToUInt16(87),
TimeOfLogReset = data.ToUInt16(89),
MeterSize = data[91],
};
if (data.Length == 93)
{
semi.CRC = data.ToUInt16(92);
}
this.semis.Push(semi);
this.NewSEMI?.Invoke(semi);
}
}
}
@@ -1,30 +0,0 @@
namespace SIRTBroadcaster.Abstraction.Parameters
{
using static SIRTBroadcaster.Abstraction.SIRTFixed;
public struct LastCMD
{
private LastCMD(byte value)
{
this.Value = value;
switch (value)
{
case WritePAM: this.Name = nameof(WritePAM); break;
case ReadPAM: this.Name = nameof(ReadPAM); break;
case WriteRAC: this.Name = nameof(WriteRAC); break;
case ReadRAC: this.Name = nameof(ReadRAC); break;
case WriteRegister: this.Name = nameof(WriteRegister); break;
case ReadRegister: this.Name = nameof(ReadRegister); break;
default: this.Name = string.Empty; break;
}
}
public byte Value { get; }
public string Name { get; }
public static implicit operator LastCMD (byte value)
=> new LastCMD(value);
}
}
@@ -1,68 +0,0 @@
namespace SIRTBroadcaster.Abstraction.Parameters
{
using SIRTBroadcaster.Abstraction.Values;
/// <summary>
/// Parameter P11 is given at third position of "Telegram from Air" telegram and give more detailed information about the
/// received packets from radio section of SIRT.The bits of Parameter 11 are decoded as following, where Bit 0 is the least
/// significant bit:
/// </summary>
public class P11 : Parameter
{
private P11(byte value) : base(value)
{
}
/// <summary>
/// Bit: 0 - RF-Module1 is source || RF-Module2 is source
/// </summary>
public Bit SourceChannel => this.bits[0];
/// <summary>
/// Bit: 1 - only one RF module data is valid || both RF module data are valid
/// </summary>
public Bit AreBothValid => this.bits[1];
/// <summary>
/// Bit: 2 - RF-Module1 data is valid || RF-Module1 data is invalid
/// </summary>
public Bit InvalidModule1 => this.bits[2];
/// <summary>
/// Bit: 3 - RF-Module2 data is valid || RF-Module2 data is invalid
/// </summary>
public Bit InvalidModule2 => this.bits[3];
/// <summary>
/// Bit: 4 - all ok || invalid -> module detects length > 128
/// </summary>
public Bit Overflow => this.bits[4];
/// <summary>
/// Bit: 5 - no attention for PAM / RAC || will look at PAM / RAC Pool
/// </summary>
public Bit Attention => this.bits[5];
/// <summary>
/// Bit: 6 -
/// If .modeSensus = 0 wireless M-busMode
/// 0: S1 - Mode
/// 1: T1 - Mode
/// If.modeSensus = 1 SensusRF
/// 0: receive at f1
/// 1: receive at f2
/// </summary>
public Bit ModeRF => this.bits[6];
/// <summary>
/// Bit: 7 - wireless M-Bus Mode || Sensus RF Mode
/// </summary>
public Bit ModeSensus => this.bits[7];
public static implicit operator P11(byte value)
=> new P11(value);
public static implicit operator byte(P11 parameter)
=> parameter.value;
}
}
@@ -1,63 +0,0 @@
namespace SIRTBroadcaster.Abstraction.Parameters
{
using SIRTBroadcaster.Abstraction.Values;
/// <summary>
/// P12 is the parameter of "Acknowledge or Answer" message and is placed at third position, if telegram from SIRT-> PC
/// begins with {0xFF, 0x12}. This parameter gives more detailed information about the last command or request which
/// was send to SIRT.Parameter 12 is given at third position of acknowledge- or answer telegram from SIRT.
/// NOTE: The bits of Parameter 12 are decoded as following, where Bit 0 is the least significant bit
/// </summary>
public class P12 : Parameter
{
private P12(byte value) : base(value)
{
}
/// <summary>
/// Bit: 0 - ok || requested buffer is full or not available
/// </summary>
public Bit IsBufferFull => this.bits[0];
/// <summary>
/// Bit: 1 - ok || operating system is busy
/// </summary>
public Bit IsOSBusy => this.bits[1];
/// <summary>
/// Bit: 2 - ok || wrong CRC recognized
/// </summary>
public Bit IsWrongCRC => this.bits[2];
/// <summary>
/// Bit: 3 - ok || command cannot be executed
/// </summary>
public Bit IsCmdNotExecuted => this.bits[3];
/// <summary>
/// Bit: 4 - ok || telegram / command byte unknown
/// </summary>
public Bit IsCmdUnknown => this.bits[4];
/// <summary>
/// Bit: 5 - ok || no such entry found
/// </summary>
public Bit IsEntryNotFound => this.bits[5];
/// <summary>
/// Bit: 6 - ok || unknown fixed byte
/// </summary>
public Bit HasUnknownByte => this.bits[6];
/// <summary>
/// Bit: 7 - normal address || address was 0xFFFFFFFF
/// </summary>
public Bit IsWildcardAddress => this.bits[7];
public static implicit operator P12 (byte value)
=> new P12(value);
public static implicit operator byte (P12 parameter)
=> parameter.value;
}
}
@@ -1,21 +0,0 @@
namespace SIRTBroadcaster.Abstraction.Parameters
{
using SIRTBroadcaster.Abstraction.Values;
public abstract class Parameter
{
protected readonly byte value;
protected readonly Bit[] bits;
protected Parameter(byte value)
{
this.value = value;
this.bits = new Bit[8];
for (int i = 0; i < 8; i++)
{
this.bits[i] = (byte)(value >> i & 1);
}
}
}
}
@@ -1,35 +0,0 @@
namespace SIRTBroadcaster.Abstraction.Parameters
{
public struct RSSI
{
public RSSI(short rf, byte value)
{
this.Value = 0;
this.Percent = 0;
if (rf == 433)
{
this.Value = (sbyte)(0.5 * value - 140);
this.Percent = (float)(-40.316 + 0.66 * value);
}
else if (rf == 433)
{
this.Value = (sbyte)(0.5 * value - 131.3);
this.Percent = (float)(-57.6667 + 0.7333 * value);
}
if (this.Percent < 0)
{
this.Percent = 0;
}
else if (this.Percent > 100)
{
this.Percent = 100;
}
}
public sbyte Value { get; }
public float Percent { get; }
}
}
@@ -1,12 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("SIRTBroadcaster.Client")]
[assembly: AssemblyDescription("Shared library between SignalR hubs and desktop clients.")]
[assembly: AssemblyCompany("SENSUS - a Xylem brand.")]
[assembly: AssemblyProduct("SIRTBroadcaster.Client")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: ComVisible(false)]
[assembly: Guid("4221f992-599e-498c-a409-6d1e70e0a6f9")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -1,76 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4221F992-599E-498C-A409-6D1E70E0A6F9}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SIRTBroadcaster.Client</RootNamespace>
<AssemblyName>SIRTBroadcaster.Client</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</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>
</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>
<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="Messages\FromAir\BUP.cs" />
<Compile Include="Messages\FromAir\DEBUG.cs" />
<Compile Include="Parameters\LastCMD.cs" />
<Compile Include="Parameters\P11.cs" />
<Compile Include="Parameters\P12.cs" />
<Compile Include="Parameters\Parameter.cs" />
<Compile Include="Parameters\RSSI.cs" />
<Compile Include="Messages\Payload.cs" />
<Compile Include="Messages\FromAir\SEMI.cs" />
<Compile Include="SIRTBroadcasterClient.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Values\Bit.cs" />
<Compile Include="Values\RadioAddress.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" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
@@ -1,180 +0,0 @@
namespace SIRTBroadcaster.Client
{
using SIRTBroadcaster.Abstraction;
using Microsoft.AspNet.SignalR.Client;
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
public interface ISIRTBroadcasterSignalRClient : ISIRTBroadcasterClient
{
bool TryGetPayload(string sirtId, uint address, out Payload payload);
}
/// <summary>
/// Implements a SignalR client connection.
/// </summary>
public class SIRTBroadcasterClient : ISIRTBroadcaster, ISIRTBroadcasterSignalRClient
{
/// <summary>
/// TODO: Add description ...
/// </summary>
private readonly ConcurrentDictionary<string, ConcurrentDictionary<uint, Payload>> payloads;
/// <summary>
/// TODO: Add description ...
/// </summary>
private readonly ICollection<IDisposable> disposables;
/// <summary>
/// TODO: Add description ...
/// </summary>
private readonly HubConnection hubConnection;
/// <summary>
/// TODO: Add description ...
/// </summary>
private readonly IHubProxy hubProxy;
/// <summary>
/// TODO: Add description ...
/// </summary>
private bool hubConnected;
/// <summary>
/// TODO: Add description ...
/// </summary>
public SIRTBroadcasterClient(params string[] sirts)
{
this.payloads = new ConcurrentDictionary<string, ConcurrentDictionary<uint, Payload>>
(collection: sirts.ToDictionary(x => x, _ => new ConcurrentDictionary<uint, Payload>()));
this.hubConnection = new HubConnection(SIRTFixed.SIRT_URL);
this.hubProxy = this.hubConnection.CreateHubProxy(SIRTFixed.SIRT_HUB);
this.disposables = new List<IDisposable>();
this.ConfigureHubConnection();
}
public event Action<UInt32> UnitDetected;
/// <summary>
/// Disposes all disposables in this instance and clears all collections.
/// </summary>
public void Dispose()
{
try
{
foreach (var disposable in this.disposables)
{
disposable?.Dispose();
}
this.disposables.Clear();
this.hubConnection.Dispose();
}
catch (Exception)
{
// TODO: Exception logging.
}
}
/// <summary>
/// Receives messages from the SignalR hub connection.
/// Under different checks the received messages are added to the payloads collection.
/// Afterword is the <see cref="UnitDetected"/> event triggered if received message is a BUP.
/// </summary>
/// <param name="message"> - received <see cref="SIRTMessage"/>.</param>
public void MessageReceived(SIRTMessage message)
{
if (message is null)
{
return;
}
var sirtId = message.SirtId;
var address = message.Address;
var payload = this.payloads
.GetOrAdd(sirtId, new ConcurrentDictionary<uint, Payload>())
.GetOrAdd(address, new Payload(sirtId, address));
if (message.MessageType == SIRTFixed.FromAir)
{
var length = message.DataLength;
if (length == 13)
{
payload.AddBUP(message);
this.UnitDetected?.Invoke(address);
}
else if (length >= 51 && 53 <= length)
{
payload.AddDEBUG(message);
}
else if (length >= 91 && 93 <= length)
{
payload.AddSEMI(message);
}
else
{
// TODO: Do smething !?.
}
}
else if (message.MessageType == SIRTFixed.LastCMD)
{
}
else if (message.MessageType == SIRTFixed.Debug)
{
}
}
/// <summary>
/// Sends the message to the hub.
/// </summary>
/// <param name="message"></param>
public void SendMessage(SIRTMessage message)
{
if (this.hubConnected)
{
this.hubProxy.Invoke(nameof(ISIRTBroadcaster.SendMessage), message);
}
}
public bool TryGetPayload(string sirtId, uint address, out Payload payload)
{
payload = payload = this.payloads
.GetOrAdd(sirtId, new ConcurrentDictionary<uint, Payload>())
.GetOrAdd(address, new Payload(sirtId, address));
return payload != null;
}
/// <summary>
/// TODO: Add description ...
/// </summary>
private void ConfigureHubConnection()
{
this.disposables.Add(this.hubProxy.On<SIRTMessage>(nameof(ISIRTBroadcaster.MessageReceived), this.MessageReceived));
this.hubConnection.StateChanged += (args) =>
{
this.hubConnected = args.NewState == ConnectionState.Connected;
};
try
{
this.hubConnection
.Start()
.ConfigureAwait(true)
.GetAwaiter()
.GetResult();
}
catch (Exception)
{
// TODO: exception logging.
}
}
}
}
@@ -1,77 +0,0 @@
namespace SIRTBroadcaster.Abstraction.Values
{
using System;
using Newtonsoft.Json;
/// <summary>
/// Bit is a custom value type.
/// Is convertable from and to: byte, byte?, bool and bool?.
/// By default returns null.
/// </summary>
[JsonConverter(typeof(JsonBitConverter))]
public struct Bit
{
private readonly byte? bit;
public Bit(byte? bit)
=> this.bit = bit;
public override string ToString()
=> bit?.ToString();
public static implicit operator Bit (byte? bit)
=> new Bit(bit);
public static implicit operator Bit (byte bit)
=> new Bit(bit);
public static implicit operator Bit (bool bit)
=> new Bit((byte?)(bit ? 1 : 0));
public static implicit operator Bit (bool? bit)
=> new Bit(bit == null ? null : (byte?)(bit == true ? 1 : 0));
public static implicit operator byte (Bit bit)
=> bit.bit ?? 0;
public static implicit operator byte? (Bit bit)
=> bit.bit;
public static implicit operator bool? (Bit bit)
{
if (bit.bit.HasValue)
{
return bit.bit == 1;
}
return null;
}
}
public class JsonBitConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (existingValue is Bit value)
{
return value;
}
return default(byte);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is Bit existingValue)
{
writer.WriteValue((byte)existingValue);
}
}
}
}
@@ -1,87 +0,0 @@
namespace SIRTBroadcaster.Abstraction.Values
{
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
[JsonConverter(typeof(RadioAddressConverter))]
public struct RadioAddress : IEnumerable<byte>
{
private readonly uint radioAddress;
private readonly byte[] addressBytes;
public RadioAddress(uint radioAddress)
{
this.radioAddress = radioAddress;
var bytes = BitConverter.GetBytes(radioAddress);
this.addressBytes = new byte[]
{
bytes[3],
bytes[2],
bytes[1],
bytes[0],
};
}
public RadioAddress(byte[] addressBytes)
{
this.addressBytes = addressBytes;
this.radioAddress = BitConverter.ToUInt32(addressBytes, 0);
}
public int Length => this.addressBytes.Length;
public IEnumerator<byte> GetEnumerator()
{
foreach (var @byte in this.addressBytes)
{
yield return @byte;
}
}
IEnumerator IEnumerable.GetEnumerator()
=> this.GetEnumerator();
public static implicit operator RadioAddress (uint radioAddress)
=> new RadioAddress(radioAddress);
public static implicit operator uint (RadioAddress radioAddress)
=> radioAddress.radioAddress;
public static implicit operator RadioAddress (byte[] addressBytes)
=> new RadioAddress(addressBytes);
public static implicit operator byte[] (RadioAddress radioAddress)
=> radioAddress.addressBytes;
}
public class RadioAddressConverter : JsonConverter
{
public override Boolean CanConvert(Type type)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (existingValue is RadioAddress radioAddress)
{
return radioAddress;
}
return default(uint);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is RadioAddress radioAddress)
{
writer.WriteValue((uint)radioAddress);
}
}
}
}
@@ -1,5 +0,0 @@
<?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" />
</packages>
@@ -1,19 +0,0 @@
namespace SIRTBroadcaster.Host
{
using SIRTBroadcaster.Abstraction;
using System;
internal interface ISIRTListener : IDisposable
{
event Action<SIRTMessage> MessageReceived;
SIRTConnection SIRTConnection { get; }
void SendData(SIRTMessage message);
void SendData(byte[] data);
bool StartListening();
}
}
@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A9D1A99D-6E55-4394-86AD-B5C53E9225EB}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SIRTBroadcaster.Host</RootNamespace>
<AssemblyName>SIRTBroadcaster.Host</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</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>
</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>
<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="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" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
@@ -1,153 +0,0 @@
namespace SIRTBroadcaster.Host
{
using Microsoft.AspNet.SignalR.Client;
using SIRTBroadcaster.Abstraction;
using System;
using System.Collections.Generic;
/// <summary>
/// Implements a SignalR host connection.
/// Operates from and to SIRT without saving any data.
/// </summary>
public class SIRTBroadcasterHost : ISIRTBroadcaster, ISIRTBroadcasterHost
{
/// <summary>
/// This collection holds all signed events to the hub.
/// On dispose they are also disposed.
/// </summary>
private readonly ICollection<IDisposable> disposables;
/// <summary>
/// SIRT listener object.
/// </summary>
private readonly ISIRTListener sirtListener;
/// <summary>
/// Hub connection object.
/// </summary>
private readonly HubConnection hubConnection;
/// <summary>
/// Hub proxy object. Handels the hub endpoints.
/// </summary>
private readonly IHubProxy hubProxy;
/// <summary>
/// Returns the hub connection state.
/// </summary>
private bool hubConnected;
/// <summary>
/// Returns the SIRT connection state.
/// </summary>
private bool sirtConnected;
/// <summary>
/// Initializes all private members needed to start message handling.
/// Starts a hub connection.
/// Also starts sirt connection.
/// </summary>
/// <param name="sirtConnection"> - model containing informations about the sirt.</param>
public SIRTBroadcasterHost(SIRTConnection sirtConnection)
{
this.disposables = new List<IDisposable>();
this.sirtListener = new SIRTListener(sirtConnection);
this.hubConnection = new HubConnection(SIRTFixed.SIRT_URL);
this.hubProxy = this.hubConnection.CreateHubProxy(SIRTFixed.SIRT_HUB);
this.ConfigureHubConnection();
this.ConfigureSIRTListener();
}
/// <summary>
/// Disposes all disposables in this instance and clears all collections.
/// </summary>
public void Dispose()
{
try
{
this.sirtListener.Dispose();
foreach (var disposable in this.disposables)
{
disposable?.Dispose();
}
this.disposables.Clear();
this.hubConnection.Dispose();
}
catch (Exception)
{
// TODO: Exception logging.
}
}
/// <summary>
/// Sends the message to the SignalR hub if the hub is connected and the message is not null.
/// </summary>
/// <param name="message"> - to send.</param>
public void MessageReceived(SIRTMessage message)
{
if (this.hubConnected && message != null)
{
this.hubProxy.Invoke(nameof(ISIRTBroadcaster.MessageReceived), message);
}
}
/// <summary>
/// Sends the message directly to the SIRT if the SIRT is connected and the message is not null.
/// </summary>
/// <param name="message"> - to send.</param>
public void SendMessage(SIRTMessage message)
{
if (this.sirtConnected && message != null)
{
this.sirtListener.SendData(message.ToByteArray());
}
}
/// <summary>
/// Initializes the hub connection.
/// </summary>
private void ConfigureHubConnection()
{
this.disposables.Add(this.hubProxy.On<SIRTMessage>(nameof(ISIRTBroadcaster.SendMessage), this.SendMessage));
this.hubConnection.StateChanged += (args) =>
{
this.hubConnected = args.NewState == ConnectionState.Connected;
};
try
{
this.hubConnection
.Start()
.ConfigureAwait(true)
.GetAwaiter()
.GetResult();
}
catch (Exception)
{
// TODO: exception logging.
}
}
/// <summary>
/// Initializes the SIRT connection.
/// </summary>
private void ConfigureSIRTListener()
{
if (this.sirtListener.StartListening())
{
this.sirtListener.MessageReceived += this.MessageReceived;
this.sirtListener.SendData(new byte[]
{
/// SIRT init string.
0x55, 0x84, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x80, 0x01, 0x90, 0xA0, 0x16
});
this.sirtConnected = true;
}
}
}
}

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