mudbus_master_csharp project added directly to the solution

This commit is contained in:
Stoyan Zlatev 2023-09-04 13:38:00 +02:00
parent f83e576be3
commit 2adc8756bc
44 changed files with 9942 additions and 79 deletions

View File

@ -157,8 +157,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Protocols", "Protocols", "{
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MjkControlledCodeRef", "MjkControlledCodeRef", "{B4F8545B-F379-42A5-BDE9-763FD7B79598}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "modbus_master_csharp", "..\..\..\MJK\Code\C#\modbus_master_csharp\src\modbus_master_csharp\modbus_master_csharp.csproj", "{F14940F8-3C86-4BB7-A915-B021E4B3052D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagFluxToolBox", "Ui\MagFluxToolBox\MagFluxToolBox.csproj", "{A5E7CE52-3101-4E9B-B896-C2C0FADE4812}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagFluxConfig", "Hardware\WaterMeter\MagFlux\MagFluxConfig\MagFluxConfig.csproj", "{70398B99-B134-4BBD-968B-7399B70C3CE2}"
@ -189,6 +187,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonMessurementUnits", "C
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
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
Utils\DateTimeServerShared\DateTimeServerShared.projitems*{4806d89a-fbfb-41bc-aaa7-2242444bf55a}*SharedItemsImports = 4
@ -3487,70 +3487,6 @@ Global
{35726BCF-975C-4B49-BEFA-C00D90394F1D}.XP32bit|x64.Build.0 = Release|Any CPU
{35726BCF-975C-4B49-BEFA-C00D90394F1D}.XP32bit|x86.ActiveCfg = Release|Any CPU
{35726BCF-975C-4B49-BEFA-C00D90394F1D}.XP32bit|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|x64.ActiveCfg = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|x64.Build.0 = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|x86.ActiveCfg = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|x86.Build.0 = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x86.Build.0 = Release|Any CPU
{A5E7CE52-3101-4E9B-B896-C2C0FADE4812}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{A5E7CE52-3101-4E9B-B896-C2C0FADE4812}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{A5E7CE52-3101-4E9B-B896-C2C0FADE4812}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
@ -4447,6 +4383,70 @@ Global
{AFC428F5-0141-4A3F-BEF2-470A89D972F6}.XP32bit|x64.Build.0 = Release|Any CPU
{AFC428F5-0141-4A3F-BEF2-470A89D972F6}.XP32bit|x86.ActiveCfg = Release|Any CPU
{AFC428F5-0141-4A3F-BEF2-470A89D972F6}.XP32bit|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}._MANUAL_CONTROL|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.COM|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|x64.ActiveCfg = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|x64.Build.0 = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|x86.ActiveCfg = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Debug|x86.Build.0 = Debug|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.GenesisDisplayTool_V01|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.PerformTest|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.Release|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.ReleaseTest|x86.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|Any CPU.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|Any CPU.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|Mixed Platforms.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|Mixed Platforms.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x64.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x64.Build.0 = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x86.ActiveCfg = Release|Any CPU
{F14940F8-3C86-4BB7-A915-B021E4B3052D}.XP32bit|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -4517,7 +4517,6 @@ Global
{C9393A97-C0BB-4D59-A879-B572BE04CE15} = {5563DD3B-2287-4BED-97BF-F0389FF505AF}
{94579693-7AC6-4FF0-B540-1F3780E1BCFA} = {C9393A97-C0BB-4D59-A879-B572BE04CE15}
{B4F8545B-F379-42A5-BDE9-763FD7B79598} = {C9393A97-C0BB-4D59-A879-B572BE04CE15}
{F14940F8-3C86-4BB7-A915-B021E4B3052D} = {B4F8545B-F379-42A5-BDE9-763FD7B79598}
{A5E7CE52-3101-4E9B-B896-C2C0FADE4812} = {03D4F23E-7E4A-4091-BC96-036C996D351A}
{70398B99-B134-4BBD-968B-7399B70C3CE2} = {C9393A97-C0BB-4D59-A879-B572BE04CE15}
{B5DA260C-71CC-45CA-B79E-D1B376AF718C} = {C9393A97-C0BB-4D59-A879-B572BE04CE15}
@ -4533,6 +4532,7 @@ Global
{FD30EB7A-7809-4E62-9374-791D31877D6D} = {696A94BE-7237-4AE2-9E36-6059DE519971}
{17C15B79-9A9E-4079-8FE2-0E563F18CA01} = {C17363DF-A043-4F25-8EBA-2B3B078227DC}
{AFC428F5-0141-4A3F-BEF2-470A89D972F6} = {C17363DF-A043-4F25-8EBA-2B3B078227DC}
{F14940F8-3C86-4BB7-A915-B021E4B3052D} = {B4F8545B-F379-42A5-BDE9-763FD7B79598}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4BCB7B69-696C-436A-86F7-C91EA5588164}

View File

@ -59,10 +59,6 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\..\..\MJK\Code\C#\modbus_master_csharp\src\modbus_master_csharp\modbus_master_csharp.csproj">
<Project>{f14940f8-3c86-4bb7-a915-b021e4b3052d}</Project>
<Name>modbus_master_csharp</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\CommonCore.Configuration\CommonCore.Configuration.csproj">
<Project>{9eb1f659-6f73-4f65-bcab-4114fd94f5fc}</Project>
<Name>CommonCore.Configuration</Name>

View File

@ -53,8 +53,8 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\..\..\..\MJK\Code\C#\modbus_master_csharp\src\modbus_master_csharp\modbus_master_csharp.csproj">
<Project>{f14940f8-3c86-4bb7-a915-b021e4b3052d}</Project>
<ProjectReference Include="..\..\..\..\..\modbus_master_csharp\modbus_master_csharp.csproj">
<Project>{F14940F8-3C86-4BB7-A915-B021E4B3052D}</Project>
<Name>modbus_master_csharp</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\..\Utils\Logging\Logging.csproj">

View File

@ -1 +1 @@
bf6bb8fceb3db5a9977dadc407cf576684bf7127
89102b0142e574de38a9f47d370f3334e5e6c268

View File

@ -1 +1 @@
247396738e2c5d26ac00f9df05c0cc5c61d7f33a
338bdd8d71c148c9df0972f903098eb23eacf0c9

View File

@ -117,10 +117,6 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\MJK\Code\C#\modbus_master_csharp\src\modbus_master_csharp\modbus_master_csharp.csproj">
<Project>{F14940F8-3C86-4BB7-A915-B021E4B3052D}</Project>
<Name>modbus_master_csharp</Name>
</ProjectReference>
<ProjectReference Include="..\..\CommonCore\CommonCore.csproj">
<Project>{1B02C79E-0B19-43E2-8F6B-71EF0C786C97}</Project>
<Name>CommonCore</Name>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>

View File

@ -0,0 +1,111 @@
using XYLEM.Base.Files;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace XYLEM.Base
{
internal static class AppConst
{
static ProgramLogCSVFileClass _Logger = new ProgramLogCSVFileClass();
internal static ProgramLogCSVFileClass Logger { get { return _Logger; } }
internal static bool IsBeta
{
get
{
return true;
//return false;
}
}
//
// Summary:
// Gets the product version associated with this application.
//
// Returns:
// The product version.
internal static string ProductVersion
{
get { return "1.0.0.1"; }
}
/// <summary>
/// Return application MJK No.
/// Have to be manuel changed by programmer for every application to fit install!
/// </summary>
/// <returns>return ex. "840126" </returns>
internal static string ProductMainMJKNo()
{
return "MJK_MAGFLUX_MODBUS";
}
/// <summary>
/// Return MJK Programs standard folder in My documents.
/// </summary>
/// <returns>return ex. "c:\...\My Documents\MJK Automation\" </returns>
internal static string ProgramsUserFolderRootPath()
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "MJK Automation\\");
}
/// <summary>
/// Return application folder in My documents.
/// Have to be manuel changed by programmer for every application to fit install!
/// </summary>
/// <returns>return ex. "c:\...\My Documents\MJK Automation\840126\" </returns>
internal static string ProgramUserFolderRootPath()
{
return Path.Combine(ProgramsUserFolderRootPath(), ProductMainMJKNo() + "\\");
}
/// <summary>
/// Return application folder to use for user files.
/// Have to be manuel changed by programmer for every application to fit install!
/// </summary>
/// <returns>return ex. "c:\...\My Documents\MJK Automation\- UserFileSave\" </returns>
internal static string UserFileSavePath()
{
return Path.Combine(ProgramsUserFolderRootPath(), "- UserFileSave\\");
}
/// <summary>
/// Return application folder to use for program user settings .
/// Have to be manual changed by programmer for every application to fit install!
/// </summary>
/// <returns>return ex. "c:\...\My Documents\MJK Automation\840126\UserSettings\" </returns>
internal static string UserFileSettingsPath()
{
return Path.Combine(ProgramUserFolderRootPath(), "UserSettings\\");
}
/// <summary>
/// Try Create UserFileSavePath and SettingPath
/// </summary>
internal static void CreateStandardUserFolders()
{
try
{
if (!Directory.Exists(UserFileSavePath()))
{
Directory.CreateDirectory(UserFileSavePath());
}
if (!Directory.Exists(ProgramUserFolderRootPath()))
{
Directory.CreateDirectory(ProgramUserFolderRootPath());
}
}
catch (Exception ex)
{
Logger.AddToProgramLogFile(true, "Error creating default user folders ", ex.Message);
}
}
}
}

View File

@ -0,0 +1,314 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Base
{
internal static class ByteArrayExtensionClass
{
/// <summary>
/// Compare if values in to array's is equal
/// </summary>
/// <param name="array 1"></param>
/// <param name="array 2"></param>
/// <returns></returns>
public static bool Compare(this byte[] b1, byte[] b2)
{
// Validate buffers are the same length.
// This also ensures that the count does not exceed the length of either buffer.
return b1.SequenceEqual<byte>(b2);
}
/// <summary>
/// Copy a chunk of bytes from start index to a specific LongLength
/// </summary>
/// <param name="from"></param>
/// <param name="startIndex">start offset 0..x</param>
/// <param name="LongLength">LongLength of returned byte data array</param>
/// <returns>Return copy of byte data</returns>
public static byte[] Copy(this byte[] from, long startIndex, long LongLength)
{
try
{
byte[] bArray = new byte[LongLength];
Array.Copy(from, startIndex, bArray, 0, LongLength);
return bArray;
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "Copy()"));
}
}
/// <summary>
/// Copy a chunk of bytes to the end of array, starting from start offset
/// </summary>
/// <param name="from"></param>
/// <param name="startIndex">start offset 0..x</param>
/// <returns>Return copy of byte data</returns>
public static byte[] Copy(this byte[] from, long startIndex)
{
try
{
long LongLength = from.LongLength - startIndex;
byte[] bArray = new byte[LongLength];
Array.Copy(from, startIndex, bArray, 0, LongLength);
return bArray;
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "Copy()"));
}
}
/// <summary>
/// Remove a chunk of bytes at the end of array, staring from offset index
/// </summary>
/// <param name="from"></param>
/// <param name="fromIndex">offset 0..x</param>
/// <returns>Return copy of byte data</returns>
public static byte[] Remove(this byte[] from, long fromIndex)
{
try
{
byte[] bArray = new byte[fromIndex];
if (bArray.LongLength < fromIndex)
{
return from;
}
Array.Copy(from, 0, bArray, 0, fromIndex);
return bArray;
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "Remove()"));
}
}
/// <summary>
/// Copy bytes until this character
/// </summary>
/// <param name="toInSeach">bytes to find character in</param>
/// <param name="untilThisCharacter">detection character</param>
/// <returns></returns>
internal static IEnumerable<byte> CopyUntil(this IEnumerable<byte> toInSeach, char untilThisCharacter)
{
try
{
if (toInSeach != null)
{
var withCharacter = toInSeach.TakeWhile(ch => ch != untilThisCharacter);
// has any data after this
if (withCharacter.Count() > 1)
{
return withCharacter;
}
}
return null; // nothing to return
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "CopyUntil()"));
}
}
/// <summary>
/// Copy bytes after this character
/// </summary>
/// <param name="toInSeach">bytes to find character in</param>
/// <param name="afterFirstCharacterOfThis">detection character</param>
/// <returns></returns>
internal static IEnumerable<byte> CopyAfterThis(this IEnumerable<byte> toInSeach, char afterFirstCharacterOfThis)
{
try
{
if (toInSeach != null)
{
var withCharacter = toInSeach.SkipWhile(ch => ch != afterFirstCharacterOfThis);
// has any data after this
if (withCharacter.Count() > 1)
{
return withCharacter.Skip(1);
}
}
return null; // nothing to return
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "CopyAfterThis()"));
}
}
/// <summary>
/// Copy bytes after this sequence of bytes
/// </summary>
/// <param name="toSeachIn">bytes to find character in</param>
/// <param name="afterFirstCharacterOfThis">detection sequence</param>
/// <returns></returns>
internal static IEnumerable<byte> CopyAfterThis(this IEnumerable<byte> toSeachIn, IEnumerable<byte> afterSequenceThis)
{
try
{
var toSeachNow = toSeachIn;
while ((toSeachNow != null) && (toSeachNow.Count() > 0) && (afterSequenceThis != null))
{
var startCh = afterSequenceThis.First();
var sequenceLng = afterSequenceThis.Count();
toSeachNow = toSeachNow.SkipWhile(ch => ch != startCh);
// If there is data after a possible sequence.. check if it have sequnece
if ((toSeachNow.Count() > sequenceLng) && afterSequenceThis.SequenceEqual(toSeachNow.Take(sequenceLng)))
{
if (toSeachNow.Count() > sequenceLng)
{
return toSeachNow.Skip(afterSequenceThis.Count());
}
return null; // nothing after sequence to return
}
// Not found
if ((toSeachNow == null) || (toSeachNow.Count() == 0))
{
return null; // nothing to return
}
// increase to next to find next start
toSeachNow = toSeachNow.Skip(1);
}
return null; // nothing to return
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "CopyAfterThis()"));
}
}
/// <summary>
/// Swap high and low byte in a word(16bit) for all words in a byte array (use ex. to a line data correct for conversion to computer U16 from modbus u16)
/// </summary>
/// <param name="data">Data to swap (SWAP IS NOT DONE ON A COPY, BUT ON THE ARRAY GIVEN AS INPUT</param>
/// <returns>return swapped input array reference (done to help supporting single line code use ex. "var data = byteArrayNeedingSwap.SwapByteInWord();") </returns>
public static byte[] SwapByteInWord(this byte[] data)
{
try
{
if (data != null)
{
for (long i = 0; i < data.LongLength; i += 2)
{
byte b = data[i];
data[i] = data[i + 1];
data[i + 1] = b;
}
}
return data;
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "SwapByteInWord()"));
}
}
/// <summary>
/// Compare if to array's has the same content (like array1 == array2)
/// </summary>
/// <param name="array1"></param>
/// <param name="array2"></param>
/// <returns>return true if the same</returns>
public static bool IsEqual(this byte[] array1, byte[] array2)
{
try
{
if ((array1 != null) && (array2 != null) && (array1.LongLength == array2.LongLength))
{
// To speed up
var result = array1.SequenceEqual(array2);
//{
//#if (!DEBUG)
//#error Test code!!!
//#endif
//if (!result) {
// var test = "Not the same!!";
// }
//}
return result;
}
return false;// not the same
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "IsEqual()"));
}
}
/// <summary>
/// Slice an array of bytes in the same sizes
/// </summary>
/// <param name="source">Data to slice an array of bytes from</param>
/// <param name="startIndex">start in data for beginning slice of bytes</param>
/// <param name="eachSliceLength">The length of each slice of bytes</param>
/// <returns>List of byte slices with the same size</returns>
public static List<byte[]> SliceSameSize(this byte[] source, long startIndex, long eachSliceLength)
{
try
{
if (source == null)
{
return null;
}
var LongLength = source.LongLength;
var slices = new List<byte[]>();
for (long offset = startIndex; offset < LongLength; offset += eachSliceLength)
{
slices.Add(Copy(source, offset, eachSliceLength));
}
return slices;
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "SliceSameSize()"));
}
}
/// <summary>
/// Slice a single array with a specific length
/// </summary>
/// <param name="source">Data to slice an array of bytes from </param>
/// <param name="startIndex">start in data for beginning slice of bytes</param>
/// <param name="length">how long is the slice from start index</param>
/// <returns></returns>
public static byte[] Slice(this byte[] source, long startIndex, long length)
{
try
{
var returnValue = new byte[length];
Array.Copy(source, startIndex, returnValue, 0, length);
return returnValue;
}
catch (Exception ex)
{
throw new InvalidOperationException(ex.ToFuncErrorText(typeof(ByteArrayExtensionClass).ToString(), "Slice()"));
}
}
/// <summary>
/// Fill or pad array with a specific value
/// </summary>
/// <param name="data"></param>
/// <param name="valueForFill"></param>
/// <returns></returns>
public static byte[] Fill(this byte[] data, byte valueForFill)
{
if (data != null)
{
for (long i = 0; i < data.LongLength; i++)
{
data[i] = valueForFill;
}
}
return data;
}
}
}

View File

@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Base
{
internal enum TimeType
{
UTC,
Local
};
internal static class TimeConvertClass
{
/// <summary>
/// convert to a text showing file time ex. [20151201-135917]
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
internal static string ToFileTimeTxt(this DateTime time)
{
return String.Format("[{0}{1:00}{2:00}-{3:00}{4:00}{5:00}]", time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second);
}
/// <summary>
/// Convert 1970Sec to 32-bit time to Time
/// </summary>
/// <param name="timeSec1970"></param>
/// <returns></returns>
internal static TimeSpan ConvertTimeSpan(this UInt32 timeSec)
{
return new TimeSpan((int)(timeSec/3600), (int)(timeSec%3600/60), (int)(timeSec%60));
}
internal static string ConvertSecondsToTimeSpanTxt(this Int32 timeSec)
{
return (timeSec >= 0 ? "" : "-") + ((UInt32)Math.Abs(timeSec)).ConvertSecondsToTimeSpanTxt();
}
internal static string ConvertToTimeSpanTxt(this TimeSpan time)
{
if (time.Days > 0)
{
return string.Format((time.Days > 1 ? "{0} days " : "1 day ") + "{1:00}:{2:00}:{3:00}", time.Days, time.Hours, time.Minutes, time.Seconds);
}
return string.Format("{0:00}:{1:00}:{2:00}", time.Hours, time.Minutes, time.Seconds);
}
internal static string ConvertSecondsToTimeSpanTxt(this UInt32 timeSec)
{
TimeSpan time = new TimeSpan((int)(timeSec / 3600), (int)(timeSec % 3600 / 60), (int)(timeSec % 60));
return time.ConvertToTimeSpanTxt();
}
internal static string ConvertSecondsToTimeSpanTxt(this Int16 timeSec)
{
return ConvertSecondsToTimeSpanTxt((Int32)timeSec);
}
internal static string ConvertSecondsToTimeSpanTxt(this UInt16 timeSec)
{
return ConvertSecondsToTimeSpanTxt((UInt32)timeSec);
}
internal static string ConvertMinuteToTimeSpanTxt(this Int16 timeMin)
{
return ConvertSecondsToTimeSpanTxt((Int32)timeMin * 60);
}
internal static string ConvertMinuteToTimeSpanTxt(this UInt16 timeMin)
{
return ConvertSecondsToTimeSpanTxt((UInt32)timeMin * 60);
}
internal static string ConvertHourToTimeSpanTxt(this Int16 timeHour)
{
return ConvertSecondsToTimeSpanTxt((Int32)timeHour * 3600);
}
internal static string ConvertHourToTimeSpanTxt(this UInt16 timeHour)
{
return ConvertSecondsToTimeSpanTxt((UInt32)timeHour * 3600);
}
/// <summary>
/// Convert 1970Sec to 32-bit time to Time
/// </summary>
/// <param name="timeSec1970"></param>
/// <returns></returns>
internal static DateTime Convert1970SecToTime(this UInt32 timeSec1970, TimeType timetype)
{
return timetype == TimeType.Local ?
(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local)).AddSeconds(timeSec1970)
: (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddSeconds(timeSec1970);
}
/// <summary>
/// Convert Time to 1970Sec
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
internal static UInt32 ConvertTimeTo1970Sec(this DateTime time, TimeType timetype)
{
TimeSpan ts = timetype == TimeType.Local ?
(time - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local))
: (time.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc));
return Convert.ToUInt32(ts.TotalSeconds);
}
/// <summary>
/// Convert 2000Sec to 32-bit time to Time
/// </summary>
/// <param name="timeSec2000"></param>
/// <returns></returns>
internal static DateTime Convert2000SecToTime(this UInt32 timeSec2000)
{
return (new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddSeconds(timeSec2000);
}
/// <summary>
/// Convert Time to 2000Sec
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
internal static UInt32 ConvertTimeTo2000Sec(this DateTime time, TimeType timetype)
{
TimeSpan ts = timetype == TimeType.Local ?
(time - new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local))
: (time.ToUniversalTime() - new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc));
return Convert.ToUInt32(ts.TotalSeconds);
}
/// <summary>
/// Convert time to a String
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static String ToLocalDateTimeString(this DateTime time)
{
DateTime localTime;
localTime = (time.Kind == DateTimeKind.Utc) ? time.ToLocalTime() : time;
return (localTime.Year.ToString().PadLeft(4, '0') + "/" + localTime.Month.ToString().PadLeft(2, '0') + "/" + localTime.Day.ToString().PadLeft(2, '0') + " "
+ localTime.Hour.ToString().PadLeft(2, '0') + ":" + localTime.Minute.ToString().PadLeft(2, '0') + ":" + localTime.Second.ToString().PadLeft(2, '0'));
}
public static readonly bool IsLocalHourFormatAM_PM = new DateTime(2000, 1, 1, 13, 0, 0).ToLongTimeString().ToLower().Contains("pm");
}
}

View File

@ -0,0 +1,459 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Base
{
public static class DataUnionTools
{
public static byte[] Reverse(this byte[] data)
{
Array.Reverse(data);
return data;
}
}
/// <summary>
/// Convert DataObjClass.DataType to Byte
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct DataUnion
{
//----------------------------- Data String to Convert Rx to ----------------------
#region ---- Inset Data Bytes in union --------
public enum DataByteLayoutType
{
Normal,
SwapAll,
SwapWords // KellerType
}
internal UInt32 Conv32BitToLowAdrHighValue(UInt32 input)
{
return (input >> 16) | (input << 16);
}
/// <summary>
/// Convert input byte data to union data
/// </summary>
/// <param name="u16Data"></param>
/// <returns></returns>
public DataUnion PutByteArray(Byte[] bInputArray, DataByteLayoutType byteType)
{
if (byteType == DataByteLayoutType.SwapAll)
{
Array.Reverse(bInputArray);
}
//dataRxText = "";
if ((bInputArray == null) || (bInputArray.Length == 0))
{
u64Data = 0;
return this;
}
bData = bInputArray[0];
if (bInputArray.Length == 1)
{
return this;
}
bData1 = bInputArray[1];
if (bInputArray.Length == 2)
{ // 16bit / 2 x 8bit
return this;
}
bData2 = bInputArray[2];
if (bInputArray.Length == 3)
{
if (byteType == DataByteLayoutType.SwapWords)
{
throw new Exception("SwapWords Not Supported!");
}
return this;
}
bData3 = bInputArray[3];
if (bInputArray.Length == 4)
{// 32bit / 4 x 8bit
if (byteType == DataByteLayoutType.SwapWords)
{
u32Data = Conv32BitToLowAdrHighValue(u32Data);
}
return this;
}
bData4 = bInputArray[4];
if (bInputArray.Length == 5)
{
if (byteType == DataByteLayoutType.SwapWords)
{
throw new Exception("SwapWords Not Supported!");
}
return this;
}
bData5 = bInputArray[5];
if (bInputArray.Length == 6)
{
if (byteType == DataByteLayoutType.SwapWords)
{
throw new Exception("SwapWords Not Supported!");
}
return this;
}
bData6 = bInputArray[6];
if (bInputArray.Length == 7)
{
if (byteType == DataByteLayoutType.SwapWords)
{
throw new Exception("SwapWords Not Supported!");
}
return this;
}
bData7 = bInputArray[7];
if (byteType == DataByteLayoutType.SwapWords)
{ // 64bit / 8 x 8bit
throw new Exception("SwapWords Not Supported!");
}
return this;
}
#endregion
#region ---- Put data as Value in to union -----
public void PutValue(UInt32 u32DataIn)
{
u32Data = u32DataIn;
}
public void PutValue(Int32 s32DataIn)
{
s32Data = s32DataIn;
}
public void PutValue(Single f32DataIn)
{
f32Data = f32DataIn;
}
public void PutValue(UInt64 u64DataIn)
{
u64Data = u64DataIn;
}
public void PutValue(Int64 s64DataIn)
{
s64Data = s64DataIn;
}
public void PutValue(double f64DataIn)
{
f64Data = f64DataIn;
}
#endregion
#region ---- Get ByteArray from input as a value ----
public byte[] GetByteArray()
{
return new byte[] { bData, bData1, bData2, bData3, bData4, bData5, bData6, bData7 };
}
void DoTxByteLayout(ref byte[] txData, DataByteLayoutType type)
{
try
{
if ((txData == null) || (txData.Length == 0))
{
throw new Exception("Has no txData");
}
switch (type)
{
case DataByteLayoutType.SwapAll: Array.Reverse(txData); break;
case DataByteLayoutType.SwapWords:
if (txData.Length == 4)
{ // 32bit / 2 x word
byte[] firstWord = new byte[2];
Array.Copy(txData, firstWord, 2);
Array.Copy(txData, 2, txData, 0, 2);
Array.Copy(firstWord, 0, txData, 2, 2);
}
else if (txData.Length == 8)
{ // 64bit / 2 x word
throw new Exception("SwapWords Not Supported!");
}
break;
case DataByteLayoutType.Normal: break; // Do nothing
default: throw new Exception("Unkown type = " + type.ToString());
}
}
catch (Exception ex)
{
throw new Exception("Error in " + this + " in func. DoTxByteLayout()! message = " + ex.Message);
}
}
/// <summary>
/// Convert to Tx data to unsigned 16bit
/// </summary>
/// <param name="u16Data"></param>
/// <returns></returns>
public byte[] GetByteArray(UInt16 u16DataIn, DataByteLayoutType byteType)
{
byte[] bDataRet = new byte[2];
u16Data = u16DataIn;
bDataRet[0] = bData;
bDataRet[1] = bData1;
DoTxByteLayout(ref bDataRet, byteType);
return bDataRet;
}
/// <summary>
/// Convert to Tx data to signed 16bit
/// </summary>
/// <param name="s16Data"></param>
/// <returns></returns>
public byte[] GetByteArray(Int16 s16DataIn, DataByteLayoutType byteType)
{
byte[] bDataRet = new byte[2];
s16Data = s16DataIn;
bDataRet[0] = bData;
bDataRet[1] = bData1;
DoTxByteLayout(ref bDataRet, byteType);
return bDataRet;
}
/// <summary>
/// Convert to Tx data to unsigned 32bit
/// </summary>
/// <param name="u32Data"></param>
/// <returns></returns>
public byte[] GetByteArray(UInt32 u32DataIn, DataByteLayoutType byteType)
{
PutValue(u32DataIn);
byte[] bDataRet = new byte[4];
bDataRet[0] = bData;
bDataRet[1] = bData1;
bDataRet[2] = bData2;
bDataRet[3] = bData3;
DoTxByteLayout(ref bDataRet, byteType);
return bDataRet;
}
/// <summary>
/// Convert to Tx data to sign 32bit
/// </summary>
/// <param name="s32Data"></param>
/// <returns></returns>
public byte[] GetByteArray(Int32 s32DataIn, DataByteLayoutType byteType)
{
PutValue(s32DataIn);
byte[] bDataRet = new byte[4];
bDataRet[0] = bData;
bDataRet[1] = bData1;
bDataRet[2] = bData2;
bDataRet[3] = bData3;
DoTxByteLayout(ref bDataRet, byteType);
return bDataRet;
}
/// <summary>
/// Convert to Tx data to Single 32bit
/// </summary>
/// <param name="f32Data"></param>
/// <returns></returns>
public byte[] GetByteArray(Single f32DataIn, DataByteLayoutType byteType)
{
PutValue(f32DataIn);
byte[] bDataRet = new byte[4];
bDataRet[0] = bData;
bDataRet[1] = bData1;
bDataRet[2] = bData2;
bDataRet[3] = bData3;
DoTxByteLayout(ref bDataRet, byteType);
return bDataRet;
}
/// <summary>
/// Convert to Tx data to unsigned 64bit
/// </summary>
/// <param name="U64Data"></param>
/// <returns></returns>
public byte[] GetByteArray(UInt64 u64DataIn, DataByteLayoutType byteType)
{
PutValue(u64DataIn);
byte[] bDataRet = new byte[8];
bDataRet[0] = bData;
bDataRet[1] = bData1;
bDataRet[2] = bData2;
bDataRet[3] = bData3;
bDataRet[4] = bData4;
bDataRet[5] = bData5;
bDataRet[6] = bData6;
bDataRet[7] = bData7;
DoTxByteLayout(ref bDataRet, byteType);
return bDataRet;
}
/// <summary>
/// Convert to Tx data to double (F64bit)
/// </summary>
/// <param name="S64Data"></param>
/// <returns></returns>
public byte[] GetByteArray(Int64 s64DataIn, DataByteLayoutType byteType)
{
PutValue(s64DataIn);
byte[] bDataRet = new byte[8];
bDataRet[0] = bData;
bDataRet[1] = bData1;
bDataRet[2] = bData2;
bDataRet[3] = bData3;
bDataRet[4] = bData4;
bDataRet[5] = bData5;
bDataRet[6] = bData6;
bDataRet[7] = bData7;
DoTxByteLayout(ref bDataRet, byteType);
return bDataRet;
}
/// <summary>
/// Convert to Tx data to unsigned 64bit
/// </summary>
/// <param name="U64Data"></param>
/// <returns></returns>
public byte[] GetByteArray(double f64DataIn, DataByteLayoutType byteType)
{
PutValue(f64DataIn);
byte[] bDataRet = new byte[8];
bDataRet[0] = bData;
bDataRet[1] = bData1;
bDataRet[2] = bData2;
bDataRet[3] = bData3;
bDataRet[4] = bData4;
bDataRet[5] = bData5;
bDataRet[6] = bData6;
bDataRet[7] = bData7;
DoTxByteLayout(ref bDataRet, byteType);
return bDataRet;
}
#endregion
#region ---- Return Union data as a value ----
public byte U8Data { get { return bData; } set { u16Data = bData; } }
public byte U8Data0 { get { return bData; } }
public byte U8Data1 { get { return bData1; } }
public byte U8Data2 { get { return bData2; } }
public byte U8Data3 { get { return bData3; } }
public byte U8Data4 { get { return bData4; } }
public byte U8Data5 { get { return bData5; } }
public byte U8Data6 { get { return bData6; } }
public byte U8Data7 { get { return bData7; } }
public UInt16 U16Data { get { return u16Data; } set { u16Data = value; } }
public UInt16 U16Data0 { get { return u16Data; } }
public UInt16 U16Data1 { get { return u16Data1; } }
public UInt16 U16Data2 { get { return u16Data2; } }
public UInt16 U16Data3 { get { return u16Data3; } }
public Int16 S16Data { get { return s16Data; } }
public Int16 S16Data0 { get { return s16Data; } }
public Int16 S16Data1 { get { return s16Data1; } }
public Int16 S16Data2 { get { return s16Data2; } }
public Int16 S16Data3 { get { return s16Data3; } }
public UInt32 U32Data { get { return u32Data; } set { u32Data = value; } }
public UInt32 U32Data0 { get { return u32Data; } }
public UInt32 U32Data1 { get { return u32Data1; } }
public Int32 S32Data { get { return s32Data; } set { s32Data = value; } }
public Int32 S32Data0 { get { return s32Data; } }
public Int32 S32Data1 { get { return s32Data1; } }
public Single F32Data { get { return f32Data; } set { f32Data = value; } }
public UInt64 U64Data { get { return u64Data; } }
public Int64 S64Data { get { return s64Data; } }
public double F64Data { get { return f64Data; } }
#endregion
/// <summary>
/// Clear all data and return emptyunion
/// </summary>
/// <returns></returns>
public DataUnion ClearData()
{
u64Data = 0;
return this;
}
#region ---- Field Union Array ----
//----------------------------- Field Union array -----------------------------
[FieldOffset(0)]
private byte bData;
[FieldOffset(1)]
private byte bData1;
[FieldOffset(2)]
private byte bData2;
[FieldOffset(3)]
private byte bData3;
[FieldOffset(4)]
private byte bData4;
[FieldOffset(5)]
private byte bData5;
[FieldOffset(6)]
private byte bData6;
[FieldOffset(7)]
private byte bData7;
[FieldOffset(0)]
private UInt16 u16Data;
[FieldOffset(2)]
private UInt16 u16Data1;
[FieldOffset(4)]
private UInt16 u16Data2;
[FieldOffset(6)]
private UInt16 u16Data3;
[FieldOffset(0)]
private Int16 s16Data;
[FieldOffset(2)]
private Int16 s16Data1;
[FieldOffset(4)]
private Int16 s16Data2;
[FieldOffset(6)]
private Int16 s16Data3;
[FieldOffset(0)]
private UInt32 u32Data;
[FieldOffset(4)]
private UInt32 u32Data1;
[FieldOffset(0)]
private Int32 s32Data;
[FieldOffset(4)]
private Int32 s32Data1;
[FieldOffset(0)]
private Single f32Data;
[FieldOffset(4)]
private Single f32Data1;
[FieldOffset(0)]
private UInt64 u64Data;
[FieldOffset(0)]
private Int64 s64Data;
[FieldOffset(0)]
private double f64Data;
#endregion
};
}

View File

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Base.Files
{
internal class PathTools
{
/// <summary>
/// File path trunk
/// </summary>
/// <param name="dirPath"> ex. c:\mainDir\subDir\text.text</param>
/// <param name="trunkLength"> ex. 12 char </param>
/// <returns> ex. will return "...\subDir\text.text" because "subDir\text.text" is > 12 </returns>
public static string FilePathStartTrunk(string dirPath, int trunkLength)
{
try
{
if (!String.IsNullOrEmpty(dirPath) && (dirPath.Length > 40))
{ // if to big .. then trunk it
var pathSplits = dirPath.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
if (pathSplits.Length > 0)
{ // are able to trunk
dirPath = "";
foreach (var item in pathSplits.Reverse())
{
dirPath = CombineDirAndFileSubPath(item, dirPath);
if (dirPath.Length > 40)
{
dirPath = CombineDirAndFileSubPath("...", dirPath);
break; // max length is now then just exit loop
}
}
}
}
return dirPath;
}
catch (Exception ex)
{
AppConst.Logger.AddFuncLog(true, "PathTools", "FilePathStartTrunk()", ex);
}
return "?";
}
/// <summary>
/// Create the directory path
/// </summary>
/// <param name="dirPath"></param>
/// <returns></returns>
public static Boolean CreateDirPath(string dirPath)
{
try
{
// Determine whether the directory exists.
if (Directory.Exists(dirPath))
{
//That path exists already
return false;
}
// Try to create the directory.
DirectoryInfo di = Directory.CreateDirectory(dirPath);
return false;
}
catch
{
return true;
}
}
/// <summary>
/// Create the directory for a file path
/// </summary>
/// <param name="pathForFile"></param>
/// <returns>return true on error</returns>
public static bool CreateDirPathForFile(string pathForFile)
{
try
{
return CreateDirPath(GetDirPath(pathForFile));
}
catch
{
return true;
}
}
/// <summary>
/// Combine a directory path and sub path to a compleate path
/// </summary>
/// <param name="dirPath"></param>
/// <param name="subFilePath"></param>
/// <returns></returns>
public static string CombineDirAndFileSubPath(string dirPath, string subFilePath)
{
dirPath = dirPath.Trim().EndsWith("\\") ?
dirPath.Trim().Remove(dirPath.LastIndexOf("\\")) :
dirPath.Trim();
return Path.Combine(dirPath, subFilePath.Trim());
}
/// <summary>
/// Get directory path
/// </summary>
/// <param name="filePath"></param>
/// <returns>return true on error</returns>
public static string GetDirPath(string filePath)
{
return filePath.Remove(filePath.Trim().LastIndexOf("\\"));
}
}
}

View File

@ -0,0 +1,212 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Base.Files
{
public class ProgramLogCSVFileClass
{
private int _LogCountErrors = -1;
private int _LogCountTotal = -1;
public int LogCountErrors { get { return _LogCountErrors; } }
public int LogCountTotal { get { return _LogCountTotal; } }
public string StdLogFilePath = null;
public event EventHandler OnErrorIsAdded;
#if (!DEBUG)
public bool DoTimeStamp = false;
#else
/*#warning DoTimeStamp is true!!!!!!!!!!!!!!!!
public bool DoTimeStamp = true;*/
public bool DoTimeStamp = false;
#endif
/// <summary>
/// init standard program logger
/// </summary>
/// <param name="stdLogFolderPath">use a custom log folder or null if use default</param>
/// <param name="filename">set a custom log file name without extension (ex. "UserCustomLogFile") or null if use default</param>
public ProgramLogCSVFileClass(string stdLogFolderPath = null, string filename = null)
{
if (String.IsNullOrEmpty(filename))
{
filename = $"{AppConst.ProductVersion}_program_log";
}
if (!string.IsNullOrEmpty(stdLogFolderPath))
{
if (!Directory.Exists(stdLogFolderPath))
{
PathTools.CreateDirPath(stdLogFolderPath);
}
StdLogFilePath=Path.Combine(stdLogFolderPath, filename + ".txt");
}
else
{
this.StdLogFilePath = Path.Combine(AppConst.ProgramUserFolderRootPath(), filename + ".txt");
#if (DEBUG)
Console.WriteLine($"Using standard program log path:\n{this.StdLogFilePath}");
#endif
}
}
/// <summary>
/// Automated get function name for the function calling this
/// Used for automating getting a function name to write in a log
/// </summary>
/// <param name="inclMsg">Add extra message to log with function name </param>
/// <returns>"[CALLING_FUNCTION_NAME]() -> [inclMsg]"</returns>
[MethodImpl(MethodImplOptions.NoInlining)]
public string GetCurrentMethod(string inclMsg = null)
{
var st = new StackTrace();
var sf = st.GetFrame(1);
var nameTxt = $"{sf.GetMethod().Name}()";
if (!String.IsNullOrEmpty(inclMsg))
{
nameTxt += " -> " + inclMsg;
}
return nameTxt;
}
internal void AddToLogFile(bool isError, string nameSingleLine, string infoMultibleLines)
{
AddToLogFile(isError, StdLogFilePath, nameSingleLine, infoMultibleLines);
}
internal void AddToLogFile(bool isError, string LogFilePath, string nameSingleLine, string infoMultibleLines)
{
try
{
if (isError)
{
_LogCountErrors++;
try
{
if (OnErrorIsAdded != null)
{
OnErrorIsAdded(null, null);
}
}
catch { } // Don't handle this if something breaks down
}
_LogCountTotal++;
if (System.IO.File.Exists(LogFilePath))
{
FileInfo f = new FileInfo(LogFilePath);
if (f.Length > (DoTimeStamp ? 1000000 : 10000))
{
f.Delete();
}
}
else
{
PathTools.CreateDirPathForFile(LogFilePath);
}
var message = infoMultibleLines;
var length = message.Length;
File.AppendAllText(LogFilePath, "¤¤¤ " + nameSingleLine.Trim() + " \"" + DateTime.Now.ToString() + "\" ¤¤¤ " + Environment.NewLine
+ message + Environment.NewLine);
#if (DEBUG)
System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff ") +
" ¤¤¤ " + nameSingleLine.Trim() + " ¤¤¤ " + Environment.NewLine
+ message
);
#endif
}
catch (Exception ex)
{ // Ups just to make sure that this don't result in program is closed
string test = ex.ToMessageText();
}
}
/// <summary>
/// Add a time stamp in program log file.. used to time differend code / controls load time
/// </summary>
/// <param name="processObj"> class or window / control obkject to make time stamp for</param>
/// <param name="desc">description text</param>
/// <param name="forceLog">Force making log and ignore DoTimeStamp setting</param>
internal void AddToTimestampLog(object processObj, string desc, bool forceLog = false)
{
try
{
if (DoTimeStamp || forceLog)
{
AddToLogFile(false, StdLogFilePath, processObj.ToString() + DateTime.Now.ToString(" [HH:mm:ss fff]"), desc);
}
}
catch { }
}
internal void AddToProgramLogFile(bool isError, string nameSingleLine, string infoMultibleLines)
{
AddToLogFile(isError, StdLogFilePath, nameSingleLine, infoMultibleLines);
}
/// <summary>
/// Add to program log
/// </summary>
/// <param name="ex">Exception to log</param>
/// <param name="isError">Is an error or just as log</param>
/// <param name="className">what class or where function is located in</param>
/// <param name="functionName">what function it was in like "myFunc()" and null if not used</param>
/// <param name="dataInfo">Additional information also to include like "while doing x and y..."</param>
internal void ToLog(Exception ex, bool isError, string className, string functionName = null, string dataInfo = null)
{
AddToProgramLogFile(isError, LogMessageTool.ToFuncText(isError, className, functionName),
(String.IsNullOrEmpty(dataInfo) ? "" : dataInfo + ((ex != null) ? Environment.NewLine : "")) // Add data info if used
+ ((ex != null) ? ex.ToMessageText() : ""));
}
internal void AddFuncLog(bool isError, string className, string functionName, string dataInfo, Exception ex)
{
ToLog(ex, isError, className, functionName, dataInfo);
}
internal void AddFuncLog(bool isError, string className, string functionName, Exception ex)
{
AddFuncLog(isError, className, functionName, null, ex);
}
internal void AddFuncLog(bool isError, string className, string functionName, string dataInfo)
{
AddFuncLog(isError, className, functionName, dataInfo, null);
}
internal void AddClassInitLog(bool isError, string className, Exception ex)
{
AddToProgramLogFile(isError, LogMessageTool.ToInitText(isError, className), ((ex != null) ? ex.ToMessageText() : ""));
}
internal void AddClassInitLog(bool isError, string className, string dataInfo, Exception ex)
{
AddToProgramLogFile(isError, LogMessageTool.ToInitText(isError, className, dataInfo), ((ex != null) ? ex.ToMessageText() : ""));
}
internal void OpenProgramLogFile()
{
OpenLogFile(StdLogFilePath);
}
internal void OpenLogFile(string LogFilePath)
{
try
{
Process.Start(LogFilePath);
}
catch (Exception ex)
{
Console.WriteLine("Error Open Log " + Environment.NewLine + ex.ToMessageText());
}
}
}
}

View File

@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Base
{
public static class LogMessageTool
{
/// <summary>
/// Return Type Name as a string
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
static public string TypeName<T>(this T obj)
{
Type t;
if (obj == null)
{
t = typeof(T);
}
else
{
t = obj.GetType();
}
return t.Name;
}
public static string ToMessageText(this Exception ex)
{
if (ex != null)
{
var message = "";
var innerMessage = "";
if (ex.InnerException != null)
{
innerMessage = ToMessageText(ex.InnerException);
}
if ((ex.Message != null) && !String.IsNullOrEmpty(ex.Message))
{
message = ex.Message;
}
if (!String.IsNullOrEmpty(innerMessage))
{
message += (!String.IsNullOrEmpty(message) ? Environment.NewLine : "") + innerMessage;
}
return message;
}
return "";
}
public static string ToFuncText(bool isError, string className, string functionName)
{
var message = (isError ? "Error in class" : "Class ") + className + " and func. " + functionName;
#if(DEBUG)
System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff ") + message);
#endif
return message;
}
public static string ToInitText(bool isError, string className)
{
var message = (isError ? "Error in init of " : "Init of ") + className;
#if(DEBUG)
System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff ") + message);
#endif
return message;
}
public static string ToInitText(bool isError, string className, string dataInfo)
{
return ToInitText(isError, className + " info = " + dataInfo);
}
public static string ToFuncErrorText(this Exception ex, string className, string functionName)
{
return ToFuncText(true, className, functionName + ((ex == null) ? "" : Environment.NewLine + "Message = " + ex.ToMessageText()));
}
public static string ToFuncErrorText(this Exception ex, string className, string functionName, string dataInfo)
{
return ToFuncText(true, className, functionName + Environment.NewLine + dataInfo + ((ex == null) ? "" : Environment.NewLine + "Message = " + ex.ToMessageText()));
}
public static string ToFuncErrorText(string className, string functionName, string dataInfo)
{
return ToFuncText(true, className, functionName + Environment.NewLine + dataInfo);
}
public static string ToFuncErrorText(string className, string functionName)
{
return ToFuncText(true, className, functionName);
}
public static string ToInitErrorText(this Exception ex, string className)
{
return ToInitText(true, className + ((ex == null) ? "" : Environment.NewLine + "Message = " + ex.ToMessageText()));
}
}
}

View File

@ -0,0 +1,602 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace XYLEM.Base
{
public static class NumberConvert
{
public static readonly string ColumnSeperatorCSV = ((2.3).ToString().Contains(".") ? "," : ";");
private static readonly int base10 = 10;
private static readonly char[] cHexa = new char[] { 'A', 'B', 'C', 'D', 'E', 'F' };
private static readonly int[] iHexaNumeric = new int[] { 10, 11, 12, 13, 14, 15 };
private static readonly int[] iHexaIndices = new int[] { 0, 1, 2, 3, 4, 5 };
private static readonly int asciiDiff = 48;
public static string PadLeft(this String text, int minLength)
{
int iCount = minLength - text.Length;
String textRet = "";
if (iCount > 0)
{
textRet = new String('0', iCount);
}
return textRet + text;
}
/// <summary>
/// Tag for values input is done as "decimal" and is placed ex. in front or behinde the value that needs to be converted
/// </summary>
public static readonly string ValueInputAsDecimalTag = "decimal";
/// <summary>
/// Tag for values input is done as "binary" and is placed ex. in front or behinde the value that needs to be converted
/// </summary>
public static readonly string ValueInputAsBinaryTag = "binary";
/// <summary>
/// Tag for values input is done as "octal" and is placed ex. in front or behinde the value that needs to be converted
/// </summary>
public static readonly string ValueInputAsOctalEndTag = "octal";
/// <summary>
/// Tag for values input is done as "0o" and is placed ex. in front the value that needs to be converted
/// </summary>
public static readonly string ValueInputAsOctalFrontTag = "0o";
/// <summary>
/// Tag for values input is done as "hex" and is placed ex. in front or behinde the value that needs to be converted
/// </summary>
public static readonly string ValueInputAsHexEndTag = "hex";
/// <summary>
/// Tag for values input is done as "0x" and is placed ex. in front the value that needs to be converted
/// </summary>
public static readonly string ValueInputAsHexFrontTag = "0x";
/// <summary>
/// Tag for values input is done as "bin" and is placed ex. in front or behinde the value that needs to be converted
/// </summary>
public static readonly string ValueInputAsBinaryEndTag = "bin";
/// <summary>
/// Tag for values input is done as "0b" and is placed ex. in front the value that needs to be converted
/// </summary>
public static readonly string ValueInputAsBinaryFrontTag = "0b";
/// <summary>
/// Convert byte values as in a string byte array
/// </summary>
/// <param name="byteValues"> must be like "0x12, 0x12, 0x12" or "1010bin; 1010bin; 1010bin" or "decimal 123, 123, 123"</param>
/// <returns></returns>
public static byte[] ValuesToBytes(this string byteValues)
{
try
{
List<byte> ret = new List<byte>();
var isHexadecimal = false;
var isDecimal = false;
var isBinary = false;
byteValues = byteValues.Trim().ToLower();
bool isBinaryMatch = (new Regex(@"^[01 ]+$")).IsMatch(byteValues);
bool isHexMatch = (new Regex(@"^[0-9a-f ]+$")).IsMatch(byteValues);
if (!string.IsNullOrEmpty(byteValues) && (byteValues.Contains(ValueInputAsHexEndTag) || byteValues.Contains("0x") || (isHexMatch && !isBinaryMatch)))
{
byteValues = byteValues.ToLower().Replace(ValueInputAsHexEndTag, "");
isHexadecimal = true;
}
else if (!string.IsNullOrEmpty(byteValues) && (byteValues.Contains(ValueInputAsDecimalTag) || isBinaryMatch))
{
byteValues = byteValues.Replace(ValueInputAsDecimalTag, "");
isDecimal = true;
}
else if (!string.IsNullOrEmpty(byteValues) && byteValues.Contains(ValueInputAsBinaryTag))
{
byteValues = byteValues.Replace(ValueInputAsBinaryTag, "");
isBinary = true;
}
var chunks = byteValues.Trim(new char[] { ' ' }).Split(new string[] { ",", ";", " ", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (var value in chunks)
{
var toConvert = value.Trim();
if (!string.IsNullOrEmpty(toConvert))
{
if (isHexadecimal || !isBinary && !isDecimal && (toConvert.StartsWith(ValueInputAsHexFrontTag) || toConvert.ToLower().Contains(ValueInputAsHexEndTag)))
{
ret.Add(Convert.ToByte(toConvert.Replace(ValueInputAsHexFrontTag, "").ToLower().Replace(ValueInputAsHexEndTag, ""), 16));
}
else if (isBinary || !isDecimal && (toConvert.StartsWith(ValueInputAsBinaryFrontTag) || toConvert.ToLower().Contains(ValueInputAsBinaryEndTag)))
{
ret.Add(Convert.ToByte(toConvert.Replace(ValueInputAsBinaryFrontTag, "").ToLower().Replace(ValueInputAsBinaryEndTag, ""), 2));
}
else
{
ret.Add(Convert.ToByte(toConvert, 10));
}
}
}
return ret.ToArray();
}
catch
{
return null; // Error
}
}
public static string UnsignedHexToDecimal(this string Hex)
{
try
{
return Convert.ToUInt64(Hex, 16).ToString();
}
catch
{
return "?";
}
}
public static string UnsignedDecimalToHex(this string iDec, int padLeft, bool Add_0x)
{
try
{
return UnsignedDecimalToHex(Convert.ToUInt64(iDec), padLeft, Add_0x);
}
catch
{
return "?";
}
}
public static string UnsignedDecimalToHex(this UInt32 iDec, int padLeft, bool Add_0x)
{
try
{
return ((Add_0x) ? ValueInputAsHexFrontTag : "") + String.Format("{0:X}", iDec).PadLeft(padLeft, '0');
}
catch
{
return "?";
}
}
public static string DecimalToHex(this Int32 iDec, int padLeft, bool Add_0x)
{
try
{
return ((Add_0x) ? ValueInputAsHexFrontTag : "") + String.Format("{0:X}", iDec).PadLeft(padLeft, '0');
}
catch
{
return "?";
}
}
public static string UnsignedDecimalToHex(this UInt64 iDec, int padLeft, bool Add_0x)
{
try
{
return ((Add_0x) ? ValueInputAsHexFrontTag : "") + String.Format("{0:X}", iDec).PadLeft(padLeft, '0');
}
catch
{
return "?";
}
}
public static string DecimalToHex(this Int64 iDec, int padLeft, bool Add_0x)
{
try
{
return ((Add_0x) ? ValueInputAsHexFrontTag : "") + String.Format("{0:X}", iDec).PadLeft(padLeft, '0');
}
catch
{
return "?";
}
}
public static string UnsignedDecimalToBin(this string dec, bool Add_0b)
{
try
{
return ((Add_0b) ? ValueInputAsBinaryFrontTag : "") + UnsignedDecimalToBase(Convert.ToUInt64(dec), 2);
}
catch
{
return "?";
}
}
static string DoAutoPadLeft(this string valueAsStr)
{
var numberToPad = (valueAsStr.Length <= 8) ? 8 : (valueAsStr.Length <= 16) ? 16 : (valueAsStr.Length <= 32) ? 32 : 64;
return valueAsStr.PadLeft(numberToPad, '0');
}
static string DoAutoSpcaePadEvery4Char(this string ValueAsStr)
{
if (String.IsNullOrEmpty(ValueAsStr))
{
return ValueAsStr;
}
else
{
ValueAsStr = ValueAsStr.Trim();
var MissingChar = ValueAsStr.Length % 4;
ValueAsStr = ValueAsStr.PadLeft(ValueAsStr.Length + 4 - MissingChar, '0');
return Regex.Replace(ValueAsStr.Trim(), @"(.{4})", "$1 ").Trim();
}
}
public static string ToUnsignedBin(this int value, bool Add_0b)
{
try
{
return ((Add_0b) ? ValueInputAsBinaryFrontTag : "") + UnsignedDecimalToBase((UInt32)value, 2).DoAutoPadLeft();
}
catch
{
return "?";
}
}
public static string ToUnsignedBin(this uint value, bool Add_0b)
{
try
{
return ((Add_0b) ? ValueInputAsBinaryFrontTag : "") + UnsignedDecimalToBase(value, 2).DoAutoPadLeft();
}
catch
{
return "?";
}
}
public static string ToUnsignedBin(this Int64 value)
{
try
{
return UnsignedDecimalToBase((UInt32)value, 2).DoAutoPadLeft();
}
catch
{
return "?";
}
}
/// <summary>
/// To string like 0bxxxxxxx depending of selection
/// </summary>
/// <param name="value">what value to show</param>
/// <param name="Add_0b">add 0b in front to indicate it is binary</param>
/// <param name="DoAutoPadLeft">"true" if pad left front with all 0 for the actual value type else "false" only pad with up to 4 bits 0 to easy read</param>
/// <returns></returns>
public static string ToUnsignedBin(this UInt64 value, bool Add_0b, bool DoAutoPadLeft = true)
{
try
{
var ret = UnsignedDecimalToBase(value, 2);
if (ret.Length == 0)
{
ret += "0"; // Always show 0 if no 1 is set
}
if (DoAutoPadLeft)
{
ret = ret.DoAutoPadLeft();
}
else
{
ret = ret.DoAutoSpcaePadEvery4Char();
}
return ((Add_0b) ? ValueInputAsBinaryFrontTag : "") + ret;
}
catch
{
return "?";
}
}
public static string ToBin(this byte value, bool Add_0b)
{
try
{
return ((Add_0b) ? ValueInputAsBinaryFrontTag : "") + UnsignedDecimalToBase(value, 2).DoAutoPadLeft();
}
catch
{
return "?";
}
}
public static string ToDec(this byte value)
{
return value.ToString("D3");
}
public static string ToHex(this byte value, bool Add_0x)
{
return DecimalToHex(value, 2, Add_0x);
}
public static string ToHex(this byte[] values, bool Add_0x, bool seperatorForCSV)
{
if (values == null) { return "Array is empty!"; }
string ret = "";
foreach (var value in values)
{
ret += (!String.IsNullOrEmpty(ret) ? (seperatorForCSV ? ColumnSeperatorCSV + " " : ", ") : "") + value.ToHex(Add_0x);
}
return ret;
}
public static string ToDec(this byte[] values)
{
if (values == null) { return "Array is empty!"; }
string ret = "";
foreach (var value in values)
{
ret += (!String.IsNullOrEmpty(ret) ? ", " : "") + value.ToDec();
}
return ret;
}
public static string ToBin(this byte[] values, bool Add_0b)
{
if (values == null) { return "Array is empty!"; }
string ret = "";
foreach (var value in values)
{
ret += (!String.IsNullOrEmpty(ret) ? ", " : "") + value.ToBin(Add_0b);
}
return ret;
}
public static string ToHex(this Int16 value, bool Add_0x)
{
return DecimalToHex(value, 4, Add_0x);
}
public static string ToHex(this UInt16 value, bool Add_0x)
{
return UnsignedDecimalToHex(value, 4, Add_0x);
}
public static string ToHex(this Int32 value, bool Add_0x)
{
return DecimalToHex(value, 8, Add_0x);
}
public static string ToHex(this UInt32 value, bool Add_0x)
{
return UnsignedDecimalToHex(value, 8, Add_0x);
}
public static string ToHex(this Int64 value, bool Add_0x)
{
return DecimalToHex(value, 16, Add_0x);
}
public static string ToHex(this UInt64 value, bool Add_0x)
{
return UnsignedDecimalToHex(value, 16, Add_0x);
}
public static string UnsignedDecimalToBase(this string iDec, int numbase)
{
try
{
return UnsignedDecimalToBase(Convert.ToUInt64(iDec), numbase);
}
catch
{
return "?";
}
}
public static string UnsignedDecimalToBase(this UInt64 iDec, int numbase)
{
try
{
String strBin = "";
int[] result = new int[64];
int MaxBit = 64;
for (; iDec > 0; iDec /= (UInt64)numbase)
{
int rem = (int)(iDec % Convert.ToUInt64(numbase));
result[--MaxBit] = rem;
}
for (int i = 0; i < result.Length; i++)
{
if ((int)result.GetValue(i) >= base10)
{
strBin += cHexa[(int)result.GetValue(i) % base10];
}
else
{
strBin += result.GetValue(i);
}
}
strBin = strBin.TrimStart(new char[] { '0' });
return strBin;
}
catch
{
return "?";
}
}
/// <summary>
/// Converter string to a value (0x or 0b is not legal)
/// </summary>
/// <param name="sBase"></param>
/// <param name="numbase"></param>
/// <returns></returns>
public static UInt64 UnsignedBaseToDecimal(this String sBase, int numbase)
{
UInt64 result = 0;
UInt64 b;
UInt64 iProduct = 1;
String sHexa = "";
if (numbase > base10)
{
for (int i = 0; i < cHexa.Length; i++)
{
sHexa += cHexa.GetValue(i).ToString();
}
}
for (int i = sBase.Length - 1; i >= 0; i--, iProduct *= (UInt64)numbase)
{
String sValue = sBase[i].ToString();
if (sValue.IndexOfAny(cHexa) >= 0)
{
b = (UInt64)iHexaNumeric[sHexa.IndexOf(sBase[i])];
}
else
{
b = (UInt64)sBase[i] - (UInt64)asciiDiff;
}
result += (b * iProduct);
}
return result;
}
/// <summary>
/// Converter string to a value use 0x or 0b
/// </summary>
/// <param name="sBase"></param>
/// <param name="numbase"></param>
/// <returns></returns>
public static UInt64 ToUInt64(this String sBase)
{
UInt64 result = 0;
UInt64 b;
UInt64 iProduct = 1;
String sHexa = "";
int numbase;
sBase = sBase.Trim().ToLower();
if (sBase.StartsWith(ValueInputAsOctalFrontTag))
{
numbase = 8;
sBase = sBase.Replace(ValueInputAsOctalFrontTag, "");
}
else if (sBase.StartsWith(ValueInputAsHexFrontTag))
{
numbase = 16;
sBase = sBase.Replace(ValueInputAsHexFrontTag, "");
}
else if (sBase.StartsWith(ValueInputAsBinaryFrontTag))
{
numbase = 2;
sBase = sBase.Replace(ValueInputAsBinaryFrontTag, "");
}
else
{
return Convert.ToUInt64(sBase);
}
if (numbase > base10)
{
for (int i = 0; i < cHexa.Length; i++)
{
sHexa += cHexa.GetValue(i).ToString();
}
}
for (int i = sBase.Length - 1; i >= 0; i--, iProduct *= (UInt64)numbase)
{
String sValue = sBase[i].ToString();
if (sValue.IndexOfAny(cHexa) >= 0)
{
b = (UInt64)iHexaNumeric[sHexa.IndexOf(sBase[i])];
}
else
{
b = (UInt64)sBase[i] - (UInt64)asciiDiff;
}
result += (b * iProduct);
}
return result;
}
/// <summary>
/// Converter string to a value use 0x or 0b
/// </summary>
/// <param name="sBase"></param>
/// <param name="numbase"></param>
/// <returns></returns>
public static Int64 ToInt64(this String sBase)
{
Int64 result = 0;
Int64 b;
Int64 iProduct = 1;
String sHexa = "";
int numbase;
bool isNegative = false;
sBase = sBase.Trim().ToLower();
if (sBase.StartsWith("-"))
{
sBase = sBase.TrimStart('-');
isNegative = true;
}
else if (sBase.StartsWith("+"))
{
sBase = sBase.TrimStart('+');
}
if (sBase.StartsWith(ValueInputAsOctalFrontTag))
{
numbase = 8;
sBase = sBase.Replace(ValueInputAsOctalFrontTag, "");
}
else if (sBase.StartsWith(ValueInputAsHexFrontTag))
{
numbase = 16;
sBase = sBase.Replace(ValueInputAsHexFrontTag, "");
}
else if (sBase.StartsWith(ValueInputAsBinaryFrontTag))
{
numbase = 2;
sBase = sBase.Replace(ValueInputAsBinaryFrontTag, "");
}
else
{
return isNegative ? -Convert.ToInt64(sBase) : Convert.ToInt64(sBase);
}
if (numbase > base10)
{
for (int i = 0; i < cHexa.Length; i++)
{
sHexa += cHexa.GetValue(i).ToString();
}
}
for (int i = sBase.Length - 1; i >= 0; i--, iProduct *= (Int64)numbase)
{
String sValue = sBase[i].ToString();
if (sValue.IndexOfAny(cHexa) >= 0)
{
b = (Int64)iHexaNumeric[sHexa.IndexOf(sBase[i])];
}
else
{
b = (Int64)sBase[i] - (Int64)asciiDiff;
}
result += (b * iProduct);
}
return isNegative ? -result : result;
}
public static UInt16 SwapByte(this UInt16 value)
{
return (UInt16)(value >> 8 | (value & 0xFF) << 8);
}
public static UInt64 SwapWord(this UInt64 value)
{
return (UInt64)(value >> 16 | (value & 0xFFFF) << 16);
}
}
}

View File

@ -0,0 +1,474 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace XYLEM.Base {
#region ---- SMS Char Convert ----
internal class UniCode {
internal UInt32 Value { get; set; }
internal char Ch {
get { return (char)Value; }
set { Value = (UInt32)value; }
}
internal string InfoTxt { get; set; }
public UniCode(UInt32 value, string infoTxt) {
Value = value;
InfoTxt = infoTxt;
}
public override string ToString( ) {
return String.Format( "\"{0}\"=0x{1x} ({2})", (char)Value, Value, InfoTxt );
}
}
// Look at /DOC/Siemens MC55i GSM-charset.pdf
// And http://www.unicode.org/Public/MAPPINGS/ETSI/GSM0338.TXT
static class StringConvertToSMSClass {
readonly static Dictionary<byte[], UniCode> ConvTable = new Dictionary<byte[], UniCode>( ){
//{ new Byte[]{0x00}, new UniCode( 0x0040 , "COMMERCIAL AT") }, TMO NOT IN USE
{ new Byte[]{0x40}, new UniCode( 0x0040, "@ Converted to \"INVERTED EXCLAMATION MARK\", Device then TX \"0x00\"") },
//{ new Byte[]{0x40}, new UniCode( 0x00A1 , "INVERTED EXCLAMATION MARK") }, TMO NOT IN USE
{ new Byte[]{0x21,0x2A}, new UniCode( 0x00A1 , "INVERTED EXCLAMATION MARK to \"!*\"") },
{ new Byte[]{0x00}, new UniCode( 0x0000 , "NULL (see note above)") },
{ new Byte[]{0x01}, new UniCode( 0x00A3 , "POUND SIGN") },
{ new Byte[]{0x02}, new UniCode( 0x0024 , "DOLLAR SIGN") },
{ new Byte[]{0x03}, new UniCode( 0x00A5 , "YEN SIGN") },
{ new Byte[]{0x04}, new UniCode( 0x00E8 , "LATIN SMALL LETTER E WITH GRAVE") },
{ new Byte[]{0x05}, new UniCode( 0x00E9 , "LATIN SMALL LETTER E WITH ACUTE") },
{ new Byte[]{0x06}, new UniCode( 0x00F9 , "LATIN SMALL LETTER U WITH GRAVE") },
{ new Byte[]{0x07}, new UniCode( 0x00EC , "LATIN SMALL LETTER I WITH GRAVE") },
{ new Byte[]{0x08}, new UniCode( 0x00F2 , "LATIN SMALL LETTER O WITH GRAVE") },
{ new Byte[]{0x09}, new UniCode( 0x00E7 , "LATIN SMALL LETTER C WITH CEDILLA") },
{ new Byte[]{0x09}, new UniCode( 0x00C7 , "LATIN CAPITAL LETTER C WITH CEDILLA (see note above)") },
{ new Byte[]{0x0A}, new UniCode( 0x000A , "LINE FEED") },
{ new Byte[]{0x0B}, new UniCode( 0x00D8 , "LATIN CAPITAL LETTER O WITH STROKE") },
{ new Byte[]{0x0C}, new UniCode( 0x00F8 , "LATIN SMALL LETTER O WITH STROKE") },
{ new Byte[]{0x0D}, new UniCode( 0x000D , "CARRIAGE RETURN") },
{ new Byte[]{0x0E}, new UniCode( 0x00C5 , "LATIN CAPITAL LETTER A WITH RING ABOVE") },
{ new Byte[]{0x0F}, new UniCode( 0x00E5 , "LATIN SMALL LETTER A WITH RING ABOVE") },
{ new Byte[]{0x10}, new UniCode( 0x0394 , "GREEK CAPITAL LETTER DELTA") },
{ new Byte[]{0x11}, new UniCode( 0x005F , "LOW LINE") },
{ new Byte[]{0x12}, new UniCode( 0x03A6 , "GREEK CAPITAL LETTER PHI") },
{ new Byte[]{0x13}, new UniCode( 0x0393 , "GREEK CAPITAL LETTER GAMMA") },
{ new Byte[]{0x14}, new UniCode( 0x039B , "GREEK CAPITAL LETTER LAMDA") },
{ new Byte[]{0x15}, new UniCode( 0x03A9 , "GREEK CAPITAL LETTER OMEGA") },
{ new Byte[]{0x16}, new UniCode( 0x03A0 , "GREEK CAPITAL LETTER PI") },
{ new Byte[]{0x17}, new UniCode( 0x03A8 , "GREEK CAPITAL LETTER PSI") },
{ new Byte[]{0x18}, new UniCode( 0x03A3 , "GREEK CAPITAL LETTER SIGMA") },
{ new Byte[]{0x19}, new UniCode( 0x0398 , "GREEK CAPITAL LETTER THETA") },
{ new Byte[]{0x1A}, new UniCode( 0x039E , "GREEK CAPITAL LETTER XI") },
{ new Byte[]{0x1B}, new UniCode( 0x00A0 , "ESCAPE TO EXTENSION TABLE (or displayed as NBSP, see note above)") },
{ new Byte[]{0x1B,0x0A}, new UniCode( 0x000C , "FORM FEED") },
{ new Byte[]{0x1B,0x14}, new UniCode( 0x005E , "CIRCUMFLEX ACCENT") },
{ new Byte[]{0x1B,0x28}, new UniCode( 0x007B , "LEFT CURLY BRACKET") },
{ new Byte[]{0x1B,0x29}, new UniCode( 0x007D , "RIGHT CURLY BRACKET") },
{ new Byte[]{0x1B,0x2F}, new UniCode( 0x005C , "REVERSE SOLIDUS") },
{ new Byte[]{0x1B,0x3C}, new UniCode( 0x005B , "LEFT SQUARE BRACKET") },
{ new Byte[]{0x1B,0x3D}, new UniCode( 0x007E , "TILDE") },
{ new Byte[]{0x1B,0x3E}, new UniCode( 0x005D , "RIGHT SQUARE BRACKET") },
{ new Byte[]{0x1B,0x40}, new UniCode( 0x007C , "VERTICAL LINE") },
{ new Byte[]{0x1B,0x65}, new UniCode( 0x20AC , "EURO SIGN") },
{ new Byte[]{0x1C}, new UniCode( 0x00C6 , "LATIN CAPITAL LETTER AE") },
{ new Byte[]{0x1D}, new UniCode( 0x00E6 , "LATIN SMALL LETTER AE") },
{ new Byte[]{0x1E}, new UniCode( 0x00DF , "LATIN SMALL LETTER SHARP S (German)") },
{ new Byte[]{0x1F}, new UniCode( 0x00C9 , "LATIN CAPITAL LETTER E WITH ACUTE") },
{ new Byte[]{0x20}, new UniCode( 0x0020 , "SPACE") },
{ new Byte[]{0x21}, new UniCode( 0x0021 , "EXCLAMATION MARK") },
{ new Byte[]{0x22}, new UniCode( 0x0022 , "QUOTATION MARK") },
{ new Byte[]{0x23}, new UniCode( 0x0023 , "NUMBER SIGN") },
{ new Byte[]{0x24}, new UniCode( 0x00A4 , "CURRENCY SIGN") },
{ new Byte[]{0x25}, new UniCode( 0x0025 , "PERCENT SIGN") },
{ new Byte[]{0x26}, new UniCode( 0x0026 , "AMPERSAND") },
{ new Byte[]{0x27}, new UniCode( 0x0027 , "APOSTROPHE") },
{ new Byte[]{0x28}, new UniCode( 0x0028 , "LEFT PARENTHESIS") },
{ new Byte[]{0x29}, new UniCode( 0x0029 , "RIGHT PARENTHESIS") },
{ new Byte[]{0x2A}, new UniCode( 0x002A , "ASTERISK") },
{ new Byte[]{0x2B}, new UniCode( 0x002B , "PLUS SIGN") },
{ new Byte[]{0x2C}, new UniCode( 0x002C , "COMMA") },
{ new Byte[]{0x2D}, new UniCode( 0x002D , "HYPHEN-MINUS") },
{ new Byte[]{0x2E}, new UniCode( 0x002E , "FULL STOP") },
{ new Byte[]{0x2F}, new UniCode( 0x002F , "SOLIDUS") },
{ new Byte[]{0x30}, new UniCode( 0x0030 , "DIGIT ZERO") },
{ new Byte[]{0x31}, new UniCode( 0x0031 , "DIGIT ONE") },
{ new Byte[]{0x32}, new UniCode( 0x0032 , "DIGIT TWO") },
{ new Byte[]{0x33}, new UniCode( 0x0033 , "DIGIT THREE") },
{ new Byte[]{0x34}, new UniCode( 0x0034 , "DIGIT FOUR") },
{ new Byte[]{0x35}, new UniCode( 0x0035 , "DIGIT FIVE") },
{ new Byte[]{0x36}, new UniCode( 0x0036 , "DIGIT SIX") },
{ new Byte[]{0x37}, new UniCode( 0x0037 , "DIGIT SEVEN") },
{ new Byte[]{0x38}, new UniCode( 0x0038 , "DIGIT EIGHT") },
{ new Byte[]{0x39}, new UniCode( 0x0039 , "DIGIT NINE") },
{ new Byte[]{0x3A}, new UniCode( 0x003A , "COLON") },
{ new Byte[]{0x3B}, new UniCode( 0x003B , "SEMICOLON") },
{ new Byte[]{0x3C}, new UniCode( 0x003C , "LESS-THAN SIGN") },
{ new Byte[]{0x3D}, new UniCode( 0x003D , "EQUALS SIGN") },
{ new Byte[]{0x3E}, new UniCode( 0x003E , "GREATER-THAN SIGN") },
{ new Byte[]{0x3F}, new UniCode( 0x003F , "QUESTION MARK") },
{ new Byte[]{0x41}, new UniCode( 0x0041 , "LATIN CAPITAL LETTER A") },
{ new Byte[]{0x41}, new UniCode( 0x0391 , "GREEK CAPITAL LETTER ALPHA") },
{ new Byte[]{0x42}, new UniCode( 0x0042 , "LATIN CAPITAL LETTER B") },
{ new Byte[]{0x42}, new UniCode( 0x0392 , "GREEK CAPITAL LETTER BETA") },
{ new Byte[]{0x43}, new UniCode( 0x0043 , "LATIN CAPITAL LETTER C") },
{ new Byte[]{0x44}, new UniCode( 0x0044 , "LATIN CAPITAL LETTER D") },
{ new Byte[]{0x45}, new UniCode( 0x0045 , "LATIN CAPITAL LETTER E") },
{ new Byte[]{0x45}, new UniCode( 0x0395 , "GREEK CAPITAL LETTER EPSILON") },
{ new Byte[]{0x46}, new UniCode( 0x0046 , "LATIN CAPITAL LETTER F") },
{ new Byte[]{0x47}, new UniCode( 0x0047 , "LATIN CAPITAL LETTER G") },
{ new Byte[]{0x48}, new UniCode( 0x0048 , "LATIN CAPITAL LETTER H") },
{ new Byte[]{0x48}, new UniCode( 0x0397 , "GREEK CAPITAL LETTER ETA") },
{ new Byte[]{0x49}, new UniCode( 0x0049 , "LATIN CAPITAL LETTER I") },
{ new Byte[]{0x49}, new UniCode( 0x0399 , "GREEK CAPITAL LETTER IOTA") },
{ new Byte[]{0x4A}, new UniCode( 0x004A , "LATIN CAPITAL LETTER J") },
{ new Byte[]{0x4B}, new UniCode( 0x004B , "LATIN CAPITAL LETTER K") },
{ new Byte[]{0x4B}, new UniCode( 0x039A , "GREEK CAPITAL LETTER KAPPA") },
{ new Byte[]{0x4C}, new UniCode( 0x004C , "LATIN CAPITAL LETTER L") },
{ new Byte[]{0x4D}, new UniCode( 0x004D , "LATIN CAPITAL LETTER M") },
{ new Byte[]{0x4D}, new UniCode( 0x039C , "GREEK CAPITAL LETTER MU") },
{ new Byte[]{0x4E}, new UniCode( 0x004E , "LATIN CAPITAL LETTER N") },
{ new Byte[]{0x4E}, new UniCode( 0x039D , "GREEK CAPITAL LETTER NU") },
{ new Byte[]{0x4F}, new UniCode( 0x004F , "LATIN CAPITAL LETTER O") },
{ new Byte[]{0x4F}, new UniCode( 0x039F , "GREEK CAPITAL LETTER OMICRON") },
{ new Byte[]{0x50}, new UniCode( 0x0050 , "LATIN CAPITAL LETTER P") },
{ new Byte[]{0x50}, new UniCode( 0x03A1 , "GREEK CAPITAL LETTER RHO") },
{ new Byte[]{0x51}, new UniCode( 0x0051 , "LATIN CAPITAL LETTER Q") },
{ new Byte[]{0x52}, new UniCode( 0x0052 , "LATIN CAPITAL LETTER R") },
{ new Byte[]{0x53}, new UniCode( 0x0053 , "LATIN CAPITAL LETTER S") },
{ new Byte[]{0x54}, new UniCode( 0x0054 , "LATIN CAPITAL LETTER T") },
{ new Byte[]{0x54}, new UniCode( 0x03A4 , "GREEK CAPITAL LETTER TAU") },
{ new Byte[]{0x55}, new UniCode( 0x0055 , "LATIN CAPITAL LETTER U") },
{ new Byte[]{0x56}, new UniCode( 0x0056 , "LATIN CAPITAL LETTER V") },
{ new Byte[]{0x57}, new UniCode( 0x0057 , "LATIN CAPITAL LETTER W") },
{ new Byte[]{0x58}, new UniCode( 0x0058 , "LATIN CAPITAL LETTER X") },
{ new Byte[]{0x58}, new UniCode( 0x03A7 , "GREEK CAPITAL LETTER CHI") },
{ new Byte[]{0x59}, new UniCode( 0x0059 , "LATIN CAPITAL LETTER Y") },
{ new Byte[]{0x59}, new UniCode( 0x03A5 , "GREEK CAPITAL LETTER UPSILON") },
{ new Byte[]{0x5A}, new UniCode( 0x005A , "LATIN CAPITAL LETTER Z") },
{ new Byte[]{0x5A}, new UniCode( 0x0396 , "GREEK CAPITAL LETTER ZETA") },
{ new Byte[]{0x5B}, new UniCode( 0x00C4 , "LATIN CAPITAL LETTER A WITH DIAERESIS") },
{ new Byte[]{0x5C}, new UniCode( 0x00D6 , "LATIN CAPITAL LETTER O WITH DIAERESIS") },
{ new Byte[]{0x5D}, new UniCode( 0x00D1 , "LATIN CAPITAL LETTER N WITH TILDE") },
{ new Byte[]{0x5E}, new UniCode( 0x00DC , "LATIN CAPITAL LETTER U WITH DIAERESIS") },
{ new Byte[]{0x5F}, new UniCode( 0x00A7 , "SECTION SIGN") },
{ new Byte[]{0x60}, new UniCode( 0x00BF , "INVERTED QUESTION MARK") },
{ new Byte[]{0x61}, new UniCode( 0x0061 , "LATIN SMALL LETTER A") },
{ new Byte[]{0x62}, new UniCode( 0x0062 , "LATIN SMALL LETTER B") },
{ new Byte[]{0x63}, new UniCode( 0x0063 , "LATIN SMALL LETTER C") },
{ new Byte[]{0x64}, new UniCode( 0x0064 , "LATIN SMALL LETTER D") },
{ new Byte[]{0x65}, new UniCode( 0x0065 , "LATIN SMALL LETTER E") },
{ new Byte[]{0x66}, new UniCode( 0x0066 , "LATIN SMALL LETTER F") },
{ new Byte[]{0x67}, new UniCode( 0x0067 , "LATIN SMALL LETTER G") },
{ new Byte[]{0x68}, new UniCode( 0x0068 , "LATIN SMALL LETTER H") },
{ new Byte[]{0x69}, new UniCode( 0x0069 , "LATIN SMALL LETTER I") },
{ new Byte[]{0x6A}, new UniCode( 0x006A , "LATIN SMALL LETTER J") },
{ new Byte[]{0x6B}, new UniCode( 0x006B , "LATIN SMALL LETTER K") },
{ new Byte[]{0x6C}, new UniCode( 0x006C , "LATIN SMALL LETTER L") },
{ new Byte[]{0x6D}, new UniCode( 0x006D , "LATIN SMALL LETTER M") },
{ new Byte[]{0x6E}, new UniCode( 0x006E , "LATIN SMALL LETTER N") },
{ new Byte[]{0x6F}, new UniCode( 0x006F , "LATIN SMALL LETTER O") },
{ new Byte[]{0x70}, new UniCode( 0x0070 , "LATIN SMALL LETTER P") },
{ new Byte[]{0x71}, new UniCode( 0x0071 , "LATIN SMALL LETTER Q") },
{ new Byte[]{0x72}, new UniCode( 0x0072 , "LATIN SMALL LETTER R") },
{ new Byte[]{0x73}, new UniCode( 0x0073 , "LATIN SMALL LETTER S") },
{ new Byte[]{0x74}, new UniCode( 0x0074 , "LATIN SMALL LETTER T") },
{ new Byte[]{0x75}, new UniCode( 0x0075 , "LATIN SMALL LETTER U") },
{ new Byte[]{0x76}, new UniCode( 0x0076 , "LATIN SMALL LETTER V") },
{ new Byte[]{0x77}, new UniCode( 0x0077 , "LATIN SMALL LETTER W") },
{ new Byte[]{0x78}, new UniCode( 0x0078 , "LATIN SMALL LETTER X") },
{ new Byte[]{0x79}, new UniCode( 0x0079 , "LATIN SMALL LETTER Y") },
{ new Byte[]{0x7A}, new UniCode( 0x007A , "LATIN SMALL LETTER Z") },
{ new Byte[]{0x7B}, new UniCode( 0x00E4 , "LATIN SMALL LETTER A WITH DIAERESIS") },
{ new Byte[]{0x7C}, new UniCode( 0x00F6 , "LATIN SMALL LETTER O WITH DIAERESIS") },
{ new Byte[]{0x7D}, new UniCode( 0x00F1 , "LATIN SMALL LETTER N WITH TILDE") },
{ new Byte[]{0x7E}, new UniCode( 0x00FC , "LATIN SMALL LETTER U WITH DIAERESIS") },
{ new Byte[]{0x7F}, new UniCode( 0x00E0 , "LATIN SMALL LETTER A WITH GRAVE") },
};
readonly static string[][] ConvertCh = new string[][]{
new string[]{ "\r", ""},
new string[]{ Environment.NewLine, "\n"},
};
internal static string RemoveIllegalATCh(this string value) {
string ret = value;
foreach (string[] replaceTxt in ConvertCh) {
if (!String.IsNullOrEmpty( replaceTxt[ 0 ] )) {
ret = ret.Replace( replaceTxt[ 0 ], "" );
}
}
return ret;
}
internal static string ReplaceIllegalATCh(this string value) {
string ret = value;
foreach (string[] replaceTxt in ConvertCh) {
if (!String.IsNullOrEmpty( replaceTxt[ 0 ] )) {
ret = ret.Replace( replaceTxt[ 0 ], replaceTxt[ 1 ] );
}
}
return ret;
}
internal static UniCode[] GetUniCodes(this byte[] data) {
try {
List<UniCode> list = new List<UniCode>( );
for (int offset = 0; offset < data.Length; offset++) {
bool found = false;
// check if byte sequens is in convert table
foreach (var code in ConvTable) {
if (data[ offset ] == code.Key.First( )) {
if (code.Key.Length == 1) {
list.Add( code.Value );
found = true;
break;
// Check if it is a combination of to bytes
} else if ((code.Key.Length == 2) && (offset + 1 < data.Length) && (data[ offset + 1 ] == code.Key[ 1 ])) {
offset++;
list.Add( code.Value );
found = true;
break;
}
}
}
if (!found) {
list.Add( new UniCode( data[ offset ], "(The Same)" ) );
}
}
return list.ToArray( );
} catch (Exception ex) {
throw new Exception( "Unable to convert data to " + typeof( UniCode ).ToString( ), ex );
}
}
internal static string ToPcChFromSmsTxt(this byte[] data) {
string txt = "";
try {
for (int offset = 0; offset < data.Length; offset++) {
bool found = false;
// check if byte sequens is in convert table
foreach (var code in ConvTable) {
if (data[ offset ] == code.Key.First( )) {
if (code.Key.Length == 1) {
txt += code.Value.Ch;
found = true;
break;
// Check if it is a combination of to bytes
} else if ((code.Key.Length == 2) && (offset + 1 < data.Length) && (data[ offset + 1 ] == code.Key[ 1 ])) {
offset++;
txt += code.Value.Ch;
found = true;
break;
}
}
}
if (!found) {
txt += (char)data[ offset ];
}
}
return txt.Replace( "\n", Environment.NewLine );
} catch (Exception ex) {
throw new Exception( "Unable to convert char after this \"" + txt + "\"", ex );
}
}
internal static byte[] ToByteFromPcChSMS(this String Txt) {
List<byte> ret = new List<byte>( );
try {
foreach (var ch in Txt.ReplaceIllegalATCh( )) {
bool found = false;
// check if byte sequens is in convert table
foreach (var code in ConvTable) {
if (ch == code.Value.Ch) {
ret.AddRange( code.Key );
found = true;
break;
}
}
if (!found) {
ret.AddRange( ASCIIEncoding.Default.GetBytes( ch.ToString( ) ) );
}
}
return ret.ToArray( );
} catch (Exception ex) {
throw new Exception( "Unable to convert char after this \"" + (ret.Count > 0 ? ret.ToArray( ).ToPcChFromSmsTxt( ) : "None, Is Empty!!") + "\"", ex );
}
}
internal static string ToStringFromPcChSMS(this String Txt) {
string ret = "";
try {
foreach (var ch in Txt.ReplaceIllegalATCh( )) {
bool found = false;
// check if byte sequens is in convert table
foreach (var code in ConvTable) {
if (ch == code.Value.Ch) {
foreach (var cdByte in code.Key) {
ret += (char)cdByte;
}
found = true;
break;
}
}
if (!found) {
foreach (var cdByte in ASCIIEncoding.Default.GetBytes( ch.ToString( ) )) {
ret += (char)cdByte;
}
}
}
return ret;
} catch (Exception ex) {
throw new Exception( "Unable to convert char after this \"" + ret + "\"", ex );
}
}
#region ---- To String ----
private static string ToInfoTxt(byte[] data, UniCode unicode) {
return string.Format( "SMS Ch = 0x{0x}{1} \t\t unicode Ch = {2}",
data.First( ), // 0
((data.Length > 1) ? string.Format( "0x{0x}", data[ 0 ] ) : ""), //1
unicode.ToString( ) ); // 2
}
public static string GetInfoTable( ) {
string txt = "";
foreach (var data in ConvTable) {
txt += ToInfoTxt( data.Key, data.Value ) + Environment.NewLine;
}
return txt;
}
#endregion
}
#endregion
internal static class StringConvert {
/// <summary>
/// Combine string array to a single text
/// </summary>
/// <param name="array">items that is null or empty will be removed</param>
/// <param name="joinWithText">inset string to join between to items (set to null if none)</param>
/// <returns></returns>
internal static string ToSingleString(this string[] array, string joinWithText) {
string ret = "";
if (array != null) {
ret = array.Select( item => (String.IsNullOrEmpty( item ) ? "" : item) ).Aggregate( (current, next) => current + ((joinWithText != null) ? joinWithText : "") + next );
}
return ret;
}
/// <summary>
/// Combine string array to a single text
/// </summary>
/// <param name="array">items that is null or empty will be removed</param>
/// <param name="addNewLine"> new line or a single space is use to join between to item</param>
/// <returns></returns>
internal static string ToSingleString(this string[] array, bool addNewLine) {
return ToSingleString( array, (addNewLine ? Environment.NewLine : " ") );
}
internal static string ToSingleString(this List<string> list, bool addNewLine) {
return ToSingleString( list.ToArray( ), addNewLine );
}
internal static string ToSingleString(this IEnumerable<string> list, bool addNewLine) {
return ToSingleString( list.ToArray( ), addNewLine );
}
internal static byte[] ToBytes(this string value) {
return ASCIIEncoding.Default.GetBytes( value );
}
/// <summary>
/// Convert PC string to at AT OK string (No new line)
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
internal static byte[] ToBytesOkATCh(this string value) {
return ASCIIEncoding.Default.GetBytes( value.RemoveIllegalATCh( ) );
}
internal static string ToPcCh(this byte[] value) {
return ASCIIEncoding.Default.GetString( value );
}
/// <summary>
/// Convert and remove all none printable char
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
internal static string ToPcPrintableCh(this byte[] value) {
return ToPcPrintableCh( value as IEnumerable<byte> );
}
/// <summary>
/// Convert and remove all none printable char
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
internal static string ToPcPrintableCh(this IEnumerable<byte> value) {
string ret = "";
if (value != null) {
foreach (var b in value) {
if (b >= 32) {
ret += ASCIIEncoding.Default.GetString( new byte[] { b } );
} else if (b == '\r') {
ret += Environment.NewLine;
}
}
}
return ret;
}
internal static string ToPcChFromATCh(this byte[] value) {
return ASCIIEncoding.Default.GetString( value ).Replace( "\r", "" ).Replace( "\n", Environment.NewLine );
}
/// <summary>
/// Get all digit sequence in a string and return it as strings
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
internal static string[] GetDecValues(this string values) {
//http://regexhero.net/tester/
//COM8.45 78.463 -676,67 6.454.54.45,4545,4545 (Selecting only the values)
//
MatchCollection matches = Regex.Matches( values, @"[-]|[.]|[-.]|[0-9][0-9]*[.]|[,]*[0-9]+" ); // ([0,1]|([0,1]?\.[0-9]+)) or "^[0-9]*[.]?[0-9]+$"
if (matches.Count != 0) {
List<string> ret = new List<string>( );
foreach (Match value in matches) {
ret.Add( value.Value );
}
return ret.ToArray( );
}
return null;
}
/// <summary>
/// Get first digit sequence in a string and return it as strings
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
internal static string GetDecValue(this string value) {
string[] values = GetDecValues( value );
if (values != null) {
return values.First( );
}
return null;
}
internal static string RemoveZeroTerm(this string value) {
if (!string.IsNullOrEmpty( value ) && value.Contains( '\0' )) {
return value.Remove( value.IndexOf( '\0' ) );
}
return value;
}
}
}

View File

@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace XYLEM.Base.XML
{
public static class XMLStringClass
{
public enum XMLVersion
{
V1_0,
V1_1
}
/// <summary>
/// Strips non-printable ascii characters
/// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1
/// </summary>
/// <param name="txtToClean"></param>
/// <returns></returns>
public static string StripIllegalXMLChars(this string txtToClean)
{
return StripIllegalXMLChars(txtToClean, XMLVersion.V1_1);
}
/// <summary>
/// Strips non-printable ascii characters
/// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1
/// Refer to http://www.w3.org/TR/2006/REC-xml-20060816/#charsets for XML 1.0
/// </summary>
/// <param name="txtToClean"></param>
/// <param name="version"></param>
/// <returns></returns>
public static string StripIllegalXMLChars(this string txtToClean, XMLVersion version)
{
try
{
string pattern = String.Empty;
txtToClean = txtToClean.
Replace("&", "&amp;").
Replace("<", "&lt;").
Replace(">", "&gt;").
Replace("\"", "&quot;").
Replace("'", "&apos;").
Replace("\r", "&#xD;").
Replace("\n", "&#xA;");
switch (version)
{
case XMLVersion.V1_0:
pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|7F|8[0-46-9A-F]9[0-9A-F])";
break;
case XMLVersion.V1_1:
pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|[19][0-9A-F]|7F|8[0-46-9A-F]|0?[1-8BCEF])";
break;
}
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
if (regex.IsMatch(txtToClean))
{
txtToClean = regex.Replace(txtToClean, String.Empty);
}
if (txtToClean.Contains('\0'))
{
txtToClean = txtToClean.Remove(txtToClean.IndexOf('\0'));
}
if (txtToClean.Contains((char)0x1E))
{
txtToClean = txtToClean.Replace((char)0x1E, ' ');
}
{
// Replace any character that has survived this done before
// Replace illegal character in XML documents with blank
// See here for reference http://www.w3.org/TR/xml/#charsets
txtToClean = Regex.Replace(txtToClean, "[\x00-\x08\x0B\x0C\x0E-\x1F]", String.Empty, RegexOptions.Compiled);
}
return txtToClean;
}
catch (Exception ex)
{
throw new Exception("Error in XMLFileIOClass and StripIllegalXMLChars() " + (txtToClean != null ? " txtToClean = " + txtToClean.ToString() : "txtToClean is null"), ex);
}
}
/// <summary>
/// reinset non-printable ascii characters
/// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1
/// </summary>
/// <param name="txtToClean"></param>
/// <returns></returns>
public static string ReinsetIllegalXMLChars(this string txtToClean)
{
return ReinsetIllegalXMLChars(txtToClean, XMLVersion.V1_1);
}
/// <summary>
/// reinset non-printable ascii characters
/// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1
/// Refer to http://www.w3.org/TR/2006/REC-xml-20060816/#charsets for XML 1.0
/// </summary>
/// <param name="txtToClean"></param>
/// <param name="version"></param>
/// <returns></returns>
public static string ReinsetIllegalXMLChars(string txtToReinset, XMLVersion version)
{
try
{
string pattern = String.Empty;
txtToReinset = txtToReinset.
Replace("&amp;", "&").
Replace("&lt;", "<").
Replace("&gt;", ">").
Replace("&quot;", "\"").
Replace("&apos;", "'").
Replace("&#xD;", "\r").
Replace("&#xA;", "\n");
return txtToReinset;
}
catch (Exception ex)
{
throw new Exception("Error in XMLFileIOClass and StripIllegalXMLChars() " + (txtToReinset != null ? " txtToClean = " + txtToReinset.ToString() : "txtToClean is null"), ex);
}
}
}
}

View File

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.Xml;
namespace XYLEM.Base.XML
{
internal class XMLWriteFuncClass
{
/// <summary>
/// Writes the given object instance to an XML file.
/// <para>Only Public properties and variables will be written to the file. These can be any type though, even other classes.</para>
/// <para>If there are public properties/variables that you do not want written to the file, decorate them with the [XmlIgnore] attribute.</para>
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToXmlFile<T>(string filePath, T objectToWrite, bool append = false) where T : new()
{
// from https://stackoverflow.com/questions/6115721/how-to-save-restore-serializable-object-to-from-file
TextWriter writer = null;
try
{
var serializer = new XmlSerializer(typeof(T));
writer = new StreamWriter(filePath, append);
serializer.Serialize(writer, objectToWrite);
}
finally
{
if (writer != null)
writer.Close();
}
}
/// <summary>
/// Reads an object instance from an XML file.
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object to read from the file.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the XML file.</returns>
public static T ReadFromXmlFile<T>(string filePath) where T : new()
{
// from https://stackoverflow.com/questions/6115721/how-to-save-restore-serializable-object-to-from-file
TextReader reader = null;
try
{
var serializer = new XmlSerializer(typeof(T));
reader = new StreamReader(filePath);
return (T)serializer.Deserialize(reader);
}
finally
{
if (reader != null)
reader.Close();
}
}
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Communication
{
/// <summary>
/// Class to contain data for a exception
/// </summary>
public struct DeviceExceptionData
{
/// <summary>
/// Special function has to be done when this com
/// https://mjksvn.world.fluidtechnology.net:4443/svn/development/- MJK Standards/- Communication protocols/Modbus/Modbus Specifications.doc
/// "2.2.1 MODBUS Exception Responses:"
/// </summary>
public enum SpecialType
{
DriverError = -1,
WaitForReset = 14, // Wait x sec befor next tx
WaitForFinishMax5s = 252, // Wait Exception OK (max 5s)
OnlyAnInforead = 253, // Used internal to only make an info read about data to read / write (Not intentet for normal TX)
WaitForFinishMax60s = 254, // Wait Exception OK (max 60s)
WaitForFinishMax5Min = 255, // Wait Exception OK (max 5min)
}
/// <summary>
/// Exception No.
/// </summary>
private int _ExcNo;
/// <summary>
/// Exception Info
/// </summary>
private string _Info;
/// <summary>
/// Preload All data.. used when init data array
/// </summary>
/// <param name="iExcNo"></param>
/// <param name="info"></param>
public DeviceExceptionData(int excNo, string info)
{
this._ExcNo = excNo;
this._Info = info;
}
/// <summary>
/// Exception code number
/// </summary>
public int ExcNo
{
get { return _ExcNo; }
set { _ExcNo = value; }
}
/// <summary>
/// Info text to exception no.
/// </summary>
public String Info
{
get { return _Info; }
set { _Info = value; }
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Communication
{
public enum Func_RD : int
{
NoSupport = -1,
No3 = 3,
No4 = 4,
};
public enum Func_WR : int
{
NoSupport = -1,
No15 = 15,
No16 = 16,
};
}

View File

@ -0,0 +1,634 @@
using MagFlux6200_metrology_reg_list;
using XYLEM.Device;
using XYLEM.Communication.ValueEncoders;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Numerics;
using System.Xml.Linq;
using static System.Net.Mime.MediaTypeNames;
using XYLEM.Base;
using System.Text.RegularExpressions;
using System.Data;
using System.Security.Policy;
using System.Threading;
namespace XYLEM.Communication
{
/// <summary>
/// Modbus read and write return data type
/// </summary>
/// <typeparam name="T"></typeparam>
public class ModbusDataResult<T> where T : IComparable, IFormattable, IComparable<T>, IEquatable<T>/*, IConvertible is not compatible with BigInteger*/
{
/// <summary>
/// Has the task succeded
/// </summary>
internal bool IsOkay;
/// <summary>
/// Data readed from or written to device
/// </summary>
internal T Data;
/// <summary>
/// What device value info for Data
/// </summary>
internal Device_value Info;
public ModbusDataResult(bool IsOkay, T DataRW, Device_value Info)
{
this.IsOkay = IsOkay;
this.Data = DataRW;
this.Info = Info;
}
}
public class ModbusDataRequest
{
/// <summary>
/// Has the task succeded
/// </summary>
internal bool IsOkay;
/// <summary>
/// Data for return read in from device
/// </summary>
internal object Data;
/// <summary>
/// What device value info for Data
/// </summary>
internal Device_value Info;
public ModbusDataRequest(bool IsOkay, object returnReadIn, Device_value Info)
{
this.IsOkay = IsOkay;
this.Data = returnReadIn;
this.Info = Info;
}
}
public class ModbusCom
{
const int ch_lng_dv = -15;
const int ch_lng_Version = -3;
const int ch_lng_MD_adr = -7;
const int dig_value = 10;
/// <summary>
/// Min delay before a DUT message is expected faild
// Is 1s for testing out that default modbus settings com don't fail
/// </summary>
private readonly int _MaxWaitForComRX_ms = 1000;
/// <summary>
/// Message ended detection delay
/// Min delay before bytes count received and haven't changed result in modbus message ended
/// The 50ms is found to be needed when using DUT RS485 and modbus messages is transparent to Metrology
/// </summary>
private readonly int _DelayBetweenRxByteCheck_ms = 50;
SerialPort _serial;
int _retry;
public int MsgErrorCount { get; private set; }
public int MsgCount { get; private set; }
public void ResetMsgCounters()
{
MsgCount = MsgErrorCount = 0;
}
public ModbusCom(string serial_port, int baudRate, Parity parity, int retry = 3)
{
ResetMsgCounters();
this._serial = new SerialPort();
_serial.PortName = serial_port;
_serial.BaudRate = baudRate;
_serial.Parity= parity;
_serial.DtrEnable = _serial.RtsEnable = true; // Need to be on for Application USB Serial com to detect a connection
//_serial.Handshake = Handshake.RequestToSendXOnXOff;
_serial.ReadTimeout = 100;
if (!_serial.IsOpen)
{
_serial.Open();
}
_retry=retry;
Console.WriteLine($"Serial connection {_serial.PortName}, {_serial.BaudRate}, {_serial.Parity}, retry = {_retry}");
}
/// <summary>
/// Is communication port connected
/// </summary>
/// <returns></returns>
public bool IsConnected()
{
return _serial.IsOpen;
}
/// <summary>
/// Generic value Read of a modbus value ex. "var ret = await Read(_serial, _device_id, req, new Single());"
/// </summary>
/// <typeparam name="T">UInt16, Single ...</typeparam>
/// <param name="device_id"> device ID to use for read</param>
/// <param name="dv"> device value to read</param>
/// <param name="retValue"> a new value of the type to read, to use for init and return</param>
/// <returns>as ModbusDataResult<T> where Item1 is true if okay and Item2 is the value read</returns>
public ModbusDataResult<T> Read<T>(int device_id, Device_value dv, T retValue) where T : IComparable, IFormattable, IComparable<T>, IEquatable<T>/*, IConvertible is not compatible with BigInteger*/
{
ModbusDataResult<T> ret = null;
try
{
byte[] answer = Read_bytes(device_id, dv.MD_adr, dv.Datatype.Length());
retValue = (T)DeviceValueEncoder.Decode(answer, dv.Datatype);
ret = new ModbusDataResult<T>(true, retValue, dv); // Okay
}
catch (Exception ex)
{
var message = $"Read error! from ID={device_id} name={dv.Name} adr={dv.MD_adr} with {dv.Datatype.Length()}\n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "Read()", message);
ret = new ModbusDataResult<T>(false, retValue, dv); // Error
}
return ret;
}
/// <summary>
/// Read multiple value optimized in one or more telegrams from device
/// </summary>
/// <param name="device_id"> Device ID to use for read</param>
/// <param name="dvList"> A list of values to read</param>
/// <returns>List with read okay or failed values</returns>
public List<ModbusDataRequest> Read(int device_id, List<Device_value> dvList)
{
List<ModbusDataRequest> ret = null;
try
{
// ----------- Generate blocks to read -----------
dvList.Sort((dvA, dvB) =>
{
return dvA.MD_adr.CompareTo(dvB.MD_adr);
});
List<List<ModbusDataRequest>> blocks = new List<List<ModbusDataRequest>>();
foreach (var dv in dvList)
{
// if first item, just add it
if ((blocks.Count == 0) || (blocks.Last().Count == 0))
{
if (blocks.Count == 0)
{
blocks.Add(new List<ModbusDataRequest>());
}
blocks.Last().Add(new ModbusDataRequest(false, null, dv));
}
else
{
var dvLast = blocks.Last().Last().Info;
// Only add it if a new value not already to be read
if (dvLast.Name != dv.Name)
{
var nextAdr = dvLast.MD_adr + (dvLast.Datatype.Length()/2);
// If not next to read in current block
if (dv.MD_adr != nextAdr)
{
// then add it to the next read block
blocks.Add(new List<ModbusDataRequest>());
}
blocks.Last().Add(new ModbusDataRequest(false, null, dv));
}
}
}
// ----------- Read blocks -----------
foreach (var dv_group in blocks)
{
try
{
var dvi_first = dv_group.First().Info;
var dvi_last = dv_group.Last().Info;
var startAdr = dvi_first.MD_adr;
var LenBytes = (dvi_last.MD_adr+(dvi_last.Datatype.Length()/2)-startAdr)*2;
if ((LenBytes < 0) || (LenBytes > 250))
{
throw new Exception($"Block length limit Error is {LenBytes}");
}
byte[] answer = Read_bytes(device_id, startAdr, LenBytes);
if (answer == null)
{
throw new Exception($"Read block error! from ID={device_id} from {dvi_first} to {dvi_last}");
}
foreach (var dv_data in dv_group)
{
var dv = dv_data.Info;
var start_idx = (dv.MD_adr-startAdr)*2;
var value_bytes = answer.Copy(start_idx, dv.Datatype.Length());
var value = DeviceValueEncoder.Decode(value_bytes, dv.Datatype);
if (ret == null)
{
ret = new List<ModbusDataRequest>();
}
ret.Add(new ModbusDataRequest(true, value, dv)); // Okay
}
}
//catch (Exception ex)
catch
{
// Retry read it as single values
foreach (var dv_data in dv_group)
{
var dv = dv_data.Info;
byte[] answer = Read_bytes(device_id, dv.MD_adr, dv.Datatype.Length());
var value = DeviceValueEncoder.Decode(answer, dv.Datatype);
if (ret == null)
{
ret = new List<ModbusDataRequest>();
}
ret.Add(new ModbusDataRequest(true, value, dv)); // Okay
}
}
}
return ret;
}
catch (Exception ex)
{
if ((dvList != null) && (dvList.Count() > 0))
{
foreach (var dv in dvList)
{
var message = $"Read error! from ID={device_id} name={dv.Name} adr={dv.MD_adr}\n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "Read()", message);
}
}
else
{
var message = $"Read error! from ID={device_id}\n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "Read()", message);
}
ret = null; // Error
}
return ret;
}
/// <summary>
/// Generic value Write of a modbus value ex. "await Write(_serial, _device_id, req, value)"
/// </summary>
/// <typeparam name="T">UInt16, Single ..</typeparam>
/// <param name="device_id"> device ID to use for write</param>
/// <param name="dv"> device value to write</param>
/// <param name="value"> the value to write</param>
/// <returns></returns>
public bool Write<T>(int device_id, Device_value dv, T value) where T : IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
bool isOkay = true;
try
{
byte[] tx_data = DeviceValueEncoder.Encode(value, dv.Datatype);
if (!Write_bytes(device_id, dv.MD_adr, tx_data))
{
var message = $"Write failed={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,-7} value={value,dig_value}";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "Write()", message);
isOkay = false;
}
}
catch (Exception ex)
{
var message = $"Write error! to ID={device_id} name={dv.Name} adr={dv.MD_adr} with {dv.Datatype.Length()}\n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "Write()", message);
isOkay = false;
}
return isOkay;
}
/// <summary>
/// Write multiple value optimized in one or more telegrams to device
/// </summary>
/// <param name="device_id"> device ID to use for write </param>
/// <param name="reqList"> a list of values to write</param>
/// <returns>A list of values written okay or failed to device</returns>
public List<ModbusDataRequest> Write(int device_id, List<ModbusDataRequest> reqList)
{
List<ModbusDataRequest> ret = null;
try
{
// ----------- Generate blocks to write -----------
reqList.Sort((dvA, dvB) =>
{
return dvA.Info.MD_adr.CompareTo(dvB.Info.MD_adr);
});
List<List<ModbusDataRequest>> blocks = new List<List<ModbusDataRequest>>();
foreach (var req in reqList)
{
// if first item, just add it
if ((blocks.Count == 0) || (blocks.Last().Count == 0))
{
if (blocks.Count == 0)
{
blocks.Add(new List<ModbusDataRequest>());
}
blocks.Last().Add(req);
}
else
{
var req_Last = blocks.Last().Last();
// Only add it if a new value not already written
if (req_Last.Info.Name != req.Info.Name)
{
var nextAdr = req_Last.Info.MD_adr + (req_Last.Info.Datatype.Length()/2);
// If not next to read in current block
if (req.Info.MD_adr != nextAdr)
{
// then add it to the next read block
blocks.Add(new List<ModbusDataRequest>());
}
blocks.Last().Add(req);
}
else
{
throw new Exception($"Only a single Write object to {req_Last.Info.Name} is allowed!");
}
}
}
// ----------- Write blocks -----------
foreach (var req_group in blocks)
{
try
{
var dvi_first = req_group.First().Info;
var dvi_last = req_group.Last().Info;
var startAdr = dvi_first.MD_adr;
var LenBytes = (dvi_last.MD_adr+(dvi_last.Datatype.Length()/2)-startAdr)*2;
if ((LenBytes < 0) || (LenBytes > 250))
{
throw new Exception($"Block length limit Error is {LenBytes}");
}
var tx_group_data = new List<byte>();
foreach (var wr in req_group)
{
byte[] tx_data = DeviceValueEncoder.Encode(wr.Data, wr.Info.Datatype);
if (tx_data == null)
{
throw new Exception($"Fail getting write byte data for {wr.Info.Name}");
}
tx_group_data.AddRange(tx_data);
}
if (LenBytes != tx_group_data.Count)
{
throw new Exception($"Group write from {dvi_first.Name} to {dvi_last.Name} expected={LenBytes} bytes, encoded was={tx_group_data.Count} bytes");
}
var isOkay = Write_bytes(device_id, startAdr, tx_group_data.ToArray());
if (!isOkay)
{
throw new Exception($"Write block error! from ID={device_id} from {dvi_first} to {dvi_last}");
}
ret = new List<ModbusDataRequest>();
foreach (var req in req_group)
{
req.IsOkay = true;
ret.Add(req); // add request that succeed
}
}
//catch (Exception ex) //For debugging
catch
{
ret = new List<ModbusDataRequest>();
// Retry write as single values
foreach (var req in req_group)
{
var dv = req.Info;
byte[] tx_data = DeviceValueEncoder.Encode(req.Data, req.Info.Datatype);
req.IsOkay = Write_bytes(device_id, dv.MD_adr, tx_data);
ret.Add(req); //
}
}
}
return ret;
}
catch (Exception ex)
{
if ((reqList != null) && (reqList.Count() > 0))
{
foreach (var dv in reqList)
{
var message = $"Write error! from ID={device_id} name={dv.Info.Name} adr={dv.Info.MD_adr}\n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "Write()", message);
}
}
else
{
var message = $"Write error! from ID={device_id}\n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "Write()", message);
}
ret = null; // Error
}
return ret;
}
/// <summary>
/// A general modbus read function for just a bunch of bytes
/// </summary>
/// <param name="device_id"> device ID to use for modbus command </param>
/// <param name="md_adr">Start address to data accessed </param>
/// <param name="num_of_bytes">Number of bytes to request</param>
/// <returns>byte data read from device and is null if none / error </returns>
public byte[] Read_bytes(int device_id, int md_adr, int num_of_bytes)
{
var is_write = false;
try
{
// Read address 0 device
var p_transate = new ProtocolTranslateModbusRTUClass();
byte[] tx_data = p_transate.CreateTxData(device_id, (int)Func_RD.No3, md_adr, num_of_bytes, null, is_write);
return modbus_com(md_adr, tx_data, is_write, p_transate);
}
catch (Exception ex)
{
var message = $"!error No data received from ID={device_id} adr={md_adr} with {num_of_bytes} to {(is_write ? "Write" : "Read")}\n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "Read_bytes()", message);
return null;
}
}
/// <summary>
/// A general modbus write function for just a bunch of bytes
/// </summary>
/// <param name="device_id"> device ID to use for modbus command </param>
/// <param name="md_adr">Start address to data accessed </param>
/// <param name="write_data">Byte data to Write</param>
/// <returns> Is true on write is okay </returns>
public bool Write_bytes(int device_id, int md_adr, byte[] write_data)
{
var is_write = true;
try
{
// Read address 0 device
var p_transate = new ProtocolTranslateModbusRTUClass();
byte[] tx_data = p_transate.CreateTxData(device_id, (int)Func_WR.No16, md_adr, write_data.Length, write_data, is_write);
var result = modbus_com(md_adr, tx_data, is_write, p_transate);
if (result != null)
{
return true; // Okay
}
}
catch (Exception ex)
{
var message = $"!error writting data to ID={device_id} adr={md_adr} to {(is_write ? "Write" : "Read")}\n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "Write_bytes()", message);
}
return false; // Error
}
/// <summary>
/// A general modbus read / write function for just a bunch of bytes
/// </summary>
/// <param name="md_adr">Start address to data accessed </param>
/// <param name="tx_data"> a complet modbus telegram byte data to transmit</param>
/// <param name="is_write"> is the modbus telegram a write or read type to use for eval received result</param>
/// <param name="p_transate">Modbus protocol translater for eval received result</param>
/// <returns>will return null on error or received message on okay</returns>
public byte[] modbus_com(int md_adr, byte[] tx_data, bool is_write, ProtocolTranslateModbusRTUClass p_transate)
{
lock (_serial)
{
try
{
byte[] answer = null;
var retry = 0;
do
{
MsgCount++;
if (!_serial.IsOpen)
{
_serial.Open();
}
_serial.DiscardInBuffer();
_serial.Write(tx_data, 0, tx_data.Length);
int received = 0;
int max_count = _MaxWaitForComRX_ms/_DelayBetweenRxByteCheck_ms;
do
{
received = _serial.BytesToRead;
Thread.Sleep(_DelayBetweenRxByteCheck_ms);
} while (((received == 0) || (received != _serial.BytesToRead)) && (--max_count>0));
if (_serial.BytesToRead <= 0)
{
MsgErrorCount++;
}
} while ((_serial.BytesToRead <= 0) && (++retry < _retry));
if (_serial.BytesToRead <= 0)
{
throw new Exception("!error No data received from device");
}
#if (DEBUG)
// TODO just testing
if (retry > 1)
{
Console.WriteLine($"Warning modbus com {retry-1} retry needed for ID={md_adr} to {(is_write ? "Write" : "Read")}");
}
#endif //#if (DEBUG)
var bytesToRead = _serial.BytesToRead;
var rx_data = new byte[bytesToRead];
var rx_data_len = _serial.Read(rx_data, 0, bytesToRead);
bool isRxRW = p_transate.IsDataRW(rx_data, true);
// Check data func is Read or write
if (isRxRW)
{
// Read
if (!is_write)
{
if (p_transate.IsRead(rx_data, true))
{
answer = p_transate.GetReadData(rx_data, true);
//buf.CallBackOK(bDataTemp, txData, CallBackOK_Single);
}
else
{
throw new Exception("Data Rx Wrong");
}
}
else // Write
{
bool isWrite = p_transate.IsWrite(rx_data, true);
int adr = p_transate.GetRxAdr(rx_data, true);
if (isWrite && (!p_transate.IsAdrPossible(rx_data, true) ? true : (adr == md_adr)))
{
//buf.CallBackOK(null, txData, CallBackOK_Single);
return rx_data; // Is okay return received message
}
else
{
throw new Exception("Data Rx Wrong");
}
}
}
else // Exception received
{
// Normal
if (!p_transate.IsRxWaitForCommand(rx_data, true))
{
int exception = p_transate.GetRxAcknowledgeCode(rx_data, true);
//buf.CallBackError(exception, txData, "");
// If read .. try again after wait
}
else
{
if (!is_write)
{
//buf.Add(txData);
// if Write.. then all must be okay and put event on delay
}
else
{
//buf.CallBackOK(null, txData, CallBackOK_Single);
}
if (p_transate.IsRxWaitForFinishMax60S(rx_data, true))
{
Thread.Sleep((int)(60 * 1000));
}
else if (p_transate.IsRxWaitForFinishMax5Min(rx_data, true))
{
Thread.Sleep((int)(5 * 60 * 1000));
}
else if (p_transate.IsRxWaitForFinishMax5S(rx_data, true))
{
Thread.Sleep((int)(5 * 1000));
}
else
{
int waitTime = 5 * 1000; // default
Thread.Sleep(waitTime); // Wait for reset
}
}
}
return answer;
}
catch (Exception ex)
{
var message = "Error: \n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "modbus_com()", message);
return null;
}
finally
{
_serial.Close();
}
}
}
}
}

View File

@ -0,0 +1,572 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using XYLEM.Base;
namespace XYLEM.Communication
{
public class ProtocolTranslateModbusRTUClass
{
public enum FunctionNumber : byte
{
NoSupport = 0,
Read_No3 = 3,
Read_No4 = 4,
Write_No15 = 15,
Write_No16 = 16,
};
/// <summary>
/// Modbus Byte Offset for write data telegram
/// </summary>
private enum BaseOffset
{
ID = 0,
FuncCode
}
/// <summary>
/// Modbus Byte Offset for write data telegram
/// </summary>
private enum TxOffset_W
{
AdrHigh = (int)BaseOffset.FuncCode + 1,
AdrLow,
RegCount_High,
RegCount_Low,
ByteCount,
Data_Start
};
/// <summary>
/// Modbus Byte Offset for read data telegram
/// </summary>
private enum TxOffset_R
{
AdrHigh = (int)BaseOffset.FuncCode + 1,
AdrLow,
RegCount_High, RegCount_Low
};
/// <summary>
/// Modbus Byte Offset for read data telegram
/// </summary>
private enum RxOffset_R
{
ByteCount = (int)BaseOffset.FuncCode + 1,
Data_Start
};
/// <summary>
/// Modbus Byte Offset for read data telegram
/// </summary>
private enum RxOffset_W
{
AdrHigh = (int)BaseOffset.FuncCode + 1,
AdrLow,
RegCount_High, RegCount_Low
};
/// <summary>
/// Modbus Byte Offset for exception data telegram
/// </summary>
private enum TxRxOffset_Exc
{
ExceptionCode = (int)BaseOffset.FuncCode + 1
};
/// <summary>
/// Calc CRC
/// </summary>
/// <param name="bByteData"></param>
/// <param name="iDataCount"></param>
/// <returns></returns>
private UInt16 CalcCrc(Byte[] bByteData, int iDataCount)
{
int u8CountByte;
byte u8Temp, u8CountBit;
UInt16 u16RetCRCvalue;
u16RetCRCvalue = 0xffff;
for (u8CountByte = 0; u8CountByte < iDataCount; u8CountByte++)
{ // Udregn CRC værdien
u16RetCRCvalue ^= bByteData[u8CountByte];
for (u8CountBit = 0; u8CountBit < 8; u8CountBit++)
{
u8Temp = (Byte)(u16RetCRCvalue & 1);
u16RetCRCvalue >>= 1;
if (u8Temp == 1)
{
u16RetCRCvalue ^= 0xa001;
}
}
}
return u16RetCRCvalue;
}
#region IProtocolTranslateClass Members
public int MaxDataReadBSize()
{
return 250; ////(252-1"Number of bytes to read")/2=125 MODBUS over _serial line specification and implementation guide V1.02 (Page 13) + Func 4/3
}
public int MaxDataWriteBSize()
{
return 230; //
}
public void StampReset() { }
public byte StampNow
{
get { return 0; } // Off
}
/// <summary>
/// Create a tx modbus message
/// </summary>
/// <param name="slaveID"></param>
/// <param name="rwFuncNo"></param>
/// <param name="adr"></param>
/// <param name="dataByteSize"></param>
/// <param name="writeData"></param>
/// <param name="IsDeviceResponse"></param>
/// <returns></returns>
public byte[] CreateTxData(int slaveID, int rwFuncNo, int adr, int dataByteSize, Byte[] writeData, bool IsDeviceResponse)
{
try
{
Byte bTemp;
Byte[] txData = null;
int count = 0, iCRC;
// Convert to modb us func number
FunctionNumber funcNo;
switch (rwFuncNo)
{
case (int)Func_RD.No3: funcNo = FunctionNumber.Read_No3; break;
case (int)Func_RD.No4: funcNo = FunctionNumber.Read_No4; break;
case (int)Func_WR.No15: funcNo = FunctionNumber.Write_No15; break;
case (int)Func_WR.No16: funcNo = FunctionNumber.Write_No16; break;
default: throw new Exception(LogMessageTool.ToFuncErrorText(this.ToString(), "CreateTxData()", "Incorrect func = " + rwFuncNo.ToString()));
}
#region ---- Read ----
if ((funcNo == FunctionNumber.Read_No3) || (funcNo == FunctionNumber.Read_No4))
{
if (IsDeviceResponse)
{
if ((writeData == null) && (dataByteSize != writeData.Length))
{
var dataBLng = (writeData == null ? 0 : writeData.Length);
throw new Exception("Data length is not the same expected " + dataByteSize + " but is " + dataBLng);
}
count = (int)RxOffset_R.Data_Start + dataByteSize;
txData = new Byte[count + 2/*to crc*/ ];
txData[(int)BaseOffset.ID] = (byte)slaveID;
txData[(int)BaseOffset.FuncCode] = (byte)funcNo;
txData[(int)RxOffset_R.ByteCount] = (byte)dataByteSize;
// Copy and Swap High And Low byte in word
for (int offset = 0; offset < dataByteSize; offset += 2)
{
bTemp = writeData[offset];
txData[(int)RxOffset_R.Data_Start + offset] = writeData[offset + 1];
txData[(int)RxOffset_R.Data_Start + offset + 1] = bTemp;
}
}
else
{
dataByteSize = (dataByteSize == 1) ? 2 : dataByteSize;
txData = new Byte[(int)TxOffset_R.RegCount_Low + 3];
txData[(int)BaseOffset.ID] = (byte)slaveID;
txData[(int)BaseOffset.FuncCode] = (byte)funcNo;
txData[(int)TxOffset_R.AdrHigh] = (byte)(adr >> 8);
txData[(int)TxOffset_R.AdrLow] = (byte)adr;
txData[(int)TxOffset_R.RegCount_High] = (byte)0;
txData[(int)TxOffset_R.RegCount_Low] = (byte)(dataByteSize >> 1);
count = (int)TxOffset_R.RegCount_Low + 1;
}
}
#endregion// Read
#region ---- Write ----
if ((funcNo == FunctionNumber.Write_No16) || (funcNo == FunctionNumber.Write_No15))
{
dataByteSize = writeData.Length;
dataByteSize = (dataByteSize == 1) ? 2 : dataByteSize;
txData = new Byte[(int)TxOffset_W.Data_Start + dataByteSize + 2];
txData[(int)BaseOffset.ID] = (byte)slaveID;
txData[(int)BaseOffset.FuncCode] = (byte)funcNo;
txData[(int)TxOffset_W.AdrHigh] = (byte)(adr >> 8);
txData[(int)TxOffset_W.AdrLow] = (byte)adr;
txData[(int)TxOffset_W.RegCount_High] = (byte)0;
txData[(int)TxOffset_W.RegCount_Low] = (byte)(dataByteSize >> 1);
txData[(int)TxOffset_W.ByteCount] = (byte)dataByteSize;
// Copy and Swap High And Low byte in word
for (count = 0; count < dataByteSize; count += 2)
{
bTemp = writeData[count];
txData[(int)TxOffset_W.Data_Start + count] = writeData[count + 1];
txData[(int)TxOffset_W.Data_Start + count + 1] = bTemp;
}
count = dataByteSize + (int)TxOffset_W.Data_Start;
}
#endregion// Write
iCRC = CalcCrc(txData, count);
txData[count] = (byte)iCRC;
txData[count + 1] = (byte)(iCRC >> 8);
return txData; // OK
}
catch
{
return null; // Error
}
}
public bool IsDataOkay(byte[] data, bool IsDeviceResponse)
{
int iCRC;
int length = (data != null) ? data.Length : 0;
iCRC = data[length - 1];
iCRC = data[length - 2] + (iCRC << 8);
return (CalcCrc(data, length - 2) == iCRC) || (CalcCrc(data, length - 2) == (((iCRC & 0xff) << 8) | (iCRC >> 8))); // Keller Fix
}
public bool IsRxDataOkay(byte[] data)
{
return IsDataOkay(data, true);
}
public bool IsDataRW(byte[] data, bool IsDeviceResponse)
{
return (data[(int)BaseOffset.FuncCode] < 0x80);
}
public bool IsRead(byte[] data, bool IsDeviceResponse)
{
return data[(int)BaseOffset.FuncCode] == (int)FunctionNumber.Read_No3
|| data[(int)BaseOffset.FuncCode] == (int)FunctionNumber.Read_No4;
}
public byte[] GetReadData(byte[] data, bool IsDeviceResponse)
{
try
{
Byte[] retData = new Byte[(int)data[(int)RxOffset_R.ByteCount]];
int offset = 0, length = 0, func = data[(int)BaseOffset.FuncCode];
if ((func == (int)FunctionNumber.Read_No3) || (func == (int)FunctionNumber.Read_No4))
{
offset = (int)RxOffset_R.Data_Start;
length = retData.Length;
if (data.Count() < length)
{
throw new Exception($"Data lng ={data.Count()} is expecting min. {length}");
}
if (length == 0)
{
return null; // Error
}
for (int iTemp = 0; (iTemp < length); iTemp += 2)
{
retData[iTemp + 1] = data[offset + iTemp];
retData[iTemp] = data[offset + iTemp + 1];
}
}
else
{
return null; // Error
}
return retData;
}
catch (Exception ex)
{
var dataAsTxt = (data==null) ? "Data is null" : data.ToHex(true, false);
var message = $"Error: data={dataAsTxt}\n\r" + ex.Message + "\n\r";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "GetReadData()", message);
throw new Exception(message);
}
}
public bool IsWrite(byte[] data, bool IsDeviceResponse)
{
return (data[(int)BaseOffset.FuncCode] == (int)FunctionNumber.Write_No16);
}
public bool IsAdrPossible(byte[] data, bool IsDeviceResponse)
{
return false;
}
public int GetRxAdr(byte[] data, bool IsDeviceResponse)
{
return ((int)data[(int)RxOffset_W.AdrHigh] << 8) | (int)data[(int)RxOffset_W.AdrLow];
}
public bool IsRxWaitForCommand(byte[] data, bool IsDeviceResponse)
{
return
(data[(int)TxRxOffset_Exc.ExceptionCode] == (int)DeviceExceptionData.SpecialType.WaitForReset)
|| IsRxWaitForFinishMax5S(data, IsDeviceResponse)
|| IsRxWaitForFinishMax60S(data, IsDeviceResponse)
|| IsRxWaitForFinishMax5Min(data, IsDeviceResponse);
}
public bool IsRxWaitForFinishMax5S(byte[] data, bool IsDeviceResponse)
{
return data[(int)TxRxOffset_Exc.ExceptionCode] == (int)DeviceExceptionData.SpecialType.WaitForFinishMax5s;
}
public bool IsRxWaitForFinishMax60S(byte[] data, bool IsDeviceResponse)
{
return data[(int)TxRxOffset_Exc.ExceptionCode] == (int)DeviceExceptionData.SpecialType.WaitForFinishMax60s;
}
public bool IsRxWaitForFinishMax5Min(byte[] data, bool IsDeviceResponse)
{
return data[(int)TxRxOffset_Exc.ExceptionCode] == (int)DeviceExceptionData.SpecialType.WaitForFinishMax5Min;
}
public bool IsAcknowledge(byte[] data, bool IsDeviceResponse)
{
return data[(int)BaseOffset.FuncCode] >= 0x80;
}
public int GetRxAcknowledgeCode(byte[] data, bool IsDeviceResponse)
{
return data[(int)TxRxOffset_Exc.ExceptionCode];
}
public ProtocolType Protocol
{
get { return ProtocolType.ModbusRTU; }
}
public int GetFuncNo(byte[] rx_data, bool IsDeviceResponse)
{
return (int)rx_data[(int)BaseOffset.FuncCode];
}
public int GetStartAdr(byte[] rx_data, bool IsDeviceResponse)
{
if (IsWrite(rx_data, IsDeviceResponse))
{
return GetRxAdr(rx_data, IsDeviceResponse);
}
else if (IsRead(rx_data, IsDeviceResponse))
{
return GetRxAdr(rx_data, IsDeviceResponse); // Is master read
}
throw new Exception("Unknown protocol type and location for start adr.");
}
public int GetNumberOfDataBytes(byte[] rx_data, bool IsDeviceResponse)
{
if (IsWrite(rx_data, IsDeviceResponse))
{
return rx_data[(int)RxOffset_W.RegCount_Low] * 2;
}
else if (IsRead(rx_data, IsDeviceResponse))
{
if (IsDeviceResponse)
{
return rx_data[(int)RxOffset_R.ByteCount];
}
else
{
return rx_data[(int)RxOffset_W.RegCount_Low] * 2;
}
}
throw new Exception("Unknown protocol type and location for number of bytes");
}
public int GetComID(byte[] rx_data, bool IsDeviceResponse)
{
return rx_data[(int)BaseOffset.ID];
}
public byte[] GetWriteData(byte[] rx_data, bool IsDeviceResponse)
{
var bytesToWrite = GetNumberOfDataBytes(rx_data, IsDeviceResponse);
try
{
var data = Base.ByteArrayExtensionClass.SwapByteInWord(rx_data.Copy((int)TxOffset_W.Data_Start, bytesToWrite));
return data;
}
catch (Exception)
{
throw new Exception("Fail to copy write data! data byte size = " + bytesToWrite);
}
}
public byte[] CreateTxData(int slaveID, int rwFuncNo, int adr, int writeResponse, bool IsDeviceResponse)
{
throw new NotImplementedException();
}
public string ToInfo(byte[] input, bool IsDeviceResponse)
{
string ret = "";
try
{
bool isOkay = IsDataOkay(input, IsDeviceResponse);
if (isOkay)
{
int id = GetComID(input, IsDeviceResponse);
int func = GetFuncNo(input, IsDeviceResponse);
ret += string.Format("Type {0}" + Environment.NewLine, IsDeviceResponse ? "Response" : "Request");
ret += string.Format("ID {0}" + Environment.NewLine, id);
bool isExeption = !IsDataRW(input, IsDeviceResponse);
try
{
var func2Test = func;
if (isExeption)
{
func2Test -= 0x80; // Get function from exeption code
ret += "Exception ";
}
ret += string.Format("Func. {0} / {1} hex", func2Test, func2Test.ToString("x"));
switch (func2Test)
{
case (int)FunctionNumber.Read_No3:
case (int)FunctionNumber.Read_No4:
ret += " is Read";
break;
case (int)FunctionNumber.Write_No15:
case (int)FunctionNumber.Write_No16:
if (IsDeviceResponse)
{
ret += " Incorrect write replay from slave!!!!";
}
else
{
ret += " is Write";
}
break;
default: ret += " Unknown func. type!"; break;
}
}
catch { ret += string.Format(" Unknown func. type!"); }
ret += Environment.NewLine;
if (isExeption)
{
var exeptioncode = (int)input[(int)BaseOffset.FuncCode + 1];
ret += string.Format("Exception code {0} / {1} hex", exeptioncode, exeptioncode.ToString("x"));
}
else
{
ret += string.Format("Number of Bytes {0}" + Environment.NewLine, GetNumberOfDataBytes(input, IsDeviceResponse));
if (IsDeviceResponse)
{
byte[] data = null;
if (IsRead(input, IsDeviceResponse))
{
data = GetReadData(input, IsDeviceResponse);
}
if (data != null)
{
data = Base.ByteArrayExtensionClass.SwapByteInWord(data);
ret += string.Format("Data is = {0}", Base.NumberConvert.ToHex(data, true, false));
}
}
else
{
byte[] data = null;
ret += string.Format("Start Address {0}" + Environment.NewLine, GetStartAdr(input, IsDeviceResponse));
if (IsWrite(input, IsDeviceResponse))
{
data = GetWriteData(input, IsDeviceResponse);
}
if (data != null)
{
data = Base.ByteArrayExtensionClass.SwapByteInWord(data);
ret += string.Format("Data is = {0}\n", Base.NumberConvert.ToHex(data, true, false));
}
}
}
//No44, // or 68 as a Special myconnect IO module telegram for https://mjksvn.world.fluidtechnology.net:4443/svn/development/8440XX Connect and myConnect/myConnect/trunk/docs/IO modules communication.docx
}
else if ((input != null) && (input.Length >= (16 + 2)))
{ // Check if it is
var telegrams = input.SliceSameSize(0, (16 + 2));
foreach (var telegram in telegrams)
{
if (IsDataOkay(telegram, IsDeviceResponse))
{
ret += "¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤" + Environment.NewLine;
int offset = 0;
ret += "ID[" + telegram[offset++] + "]";
ret += " func[" + telegram[offset++] + "]";
int Quantity = telegram[offset++];
int[] Descriptors = new int[] { telegram[offset++], 0 };
{ // print out Status
ret += Environment.NewLine;
int Status = telegram[offset++];
switch (Status)
{
case 0x11: ret += "Both recognized"; break;
case 0x01: ret += "Lower OK, upper ERROR"; break;
case 0x10: ret += "Lower ERROR, upper OK"; break;
case 0x00: ret += "Both ERROR"; break;
default: ret += "Unknown status" + Status.ToHex(true); break;
}
}
{// Print out Descriptor
ret += Environment.NewLine;
Descriptors[1] = telegram[offset++];
foreach (var Descriptor in Descriptors)
{
ret += " Type[";
switch (Descriptor)
{
case 0: ret += "none"; break;
case 1: ret += "6DI"; break;
case 2: ret += "6DO"; break;
case 3: ret += "3AI"; break;
case 4: ret += "3AO"; break;
default: ret += "Unknown" + Descriptor.ToHex(true); break;
}
ret += "]";
}
}
{// Print out data
ret += Environment.NewLine + "Raw[" + telegram.Slice(offset, telegram.Length - offset).ToHex(true, false) + "]";
var u32Values = telegram.SliceSameSize(offset, 4);
foreach (var u32Value in u32Values)
{
ret += Environment.NewLine;
ret += " DI&DO[" + u32Value[0].ToBin(true) + "]/AI&AO[" + (new DataUnion()).PutByteArray(u32Value, DataUnion.DataByteLayoutType.SwapWords).F32Data + "]";
}
}
}
else
{
ret += string.Format("Message is {0} is wrong!" + Environment.NewLine, telegram.ToHex(true, false));
}
ret += Environment.NewLine;
}
}
else
{
ret += string.Format("Message is {0}" + Environment.NewLine, isOkay ? "okay" : "CRC is wrong!");
}
}
catch (Exception ex)
{
ret += "Error = " + ex.Message;
}
return ret;
}
/// <summary>
/// Added to IProtocolTranslateClass to use in Comli
/// </summary>
public byte[] CreateTxData(int slaveID, int rwFuncNo, int adr, int dataByteSize, byte[] writeData, bool IsDeviceResponse, ref int pageNumberNow)
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
using System;
namespace XYLEM.Communication
{
//------------------------------------- Define ------------------------------------------------
public enum ProtocolType : int
{
ModbusRTU = 0,
None,
};
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace XYLEM.Communication.ValueEncoders
{
static class ArrayManipulator
{
public static byte[] SwapPairWise(byte[] input)
{
byte[] swapped = new byte[input.Length];
for (int i = 0; i < input.Length; i = i+2)
{
swapped[i + 1] = input[i];
swapped[i] = input[i + 1];
}
return swapped;
}
}
}

View File

@ -0,0 +1,952 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XYLEM.Communication;
using System.Xml;
using System.Xml.Linq;
using XYLEM.Base;
using XYLEM.Base.Files;
using XYLEM.Device.Value;
using System.Numerics;
using XYLEM.Communication.ValueEncoders;
using XYLEM.Base.XML;
namespace XYLEM.Communication.ValueEncoders
{
/// <summary>
/// Return used character set used for email or empty if not Loaded from setup
/// </summary>
/// <returns>ex. "iso-8859-1"</returns>
public delegate string GetEmailCharacterSetToUse();
public static class DeviceValueEncoder
{
public static object Default(this ValueDataType dataType)
{
try
{
switch (dataType)
{
case ValueDataType.U8:
case ValueDataType.B8: return (byte)0;
case ValueDataType.S8: return (sbyte)0;
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return (UInt16)0;
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC: return ((UInt32)0).Convert1970SecToTime(TimeType.UTC);
case ValueDataType.U32TIME_Y2000: return ((UInt32)0).Convert2000SecToTime();
case ValueDataType.U32MJK_SN: return ((UInt32)0);
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: return ((UInt32)0);
//case DeviceValueDataType.U24:
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
case ValueDataType.B32:
case ValueDataType.U32: return (UInt32)0;
case ValueDataType.B64:
case ValueDataType.U64: return (UInt64)0;
case ValueDataType.F64: return (double)0;
case ValueDataType.U128: return (BigInteger)0;
case ValueDataType.S16: return (Int16)0;
case ValueDataType.F32: return (Single)0;
//case DeviceValueDataType.U32IPV4: return "0.0.0.0"; // handled as a string
default:
if (dataType.IsText())
{ // Do this as the last check to save CPU power
return "";
}
throw new Exception(dataType.ToString() + "has no default value)");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Default()", "dataType = " + dataType.ToString()));
}
}
public static string EncodeXML(this object value, ValueDataType type)
{
try
{
string valueAsTxt = value.ToString();
switch (type)
{
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC:
if (value is DateTime)
{
var value32bit = ((DateTime)value).ConvertTimeTo1970Sec(TimeType.Local);
return XmlConvert.ToString(value32bit);
}
return XmlConvert.ToString((Double)value);
case ValueDataType.U32TIME_Y2000:
if (value is DateTime)
{
var value32bit = ((DateTime)value).ConvertTimeTo2000Sec(TimeType.Local);
return XmlConvert.ToString(value32bit);
}
return XmlConvert.ToString((Double)value);
case ValueDataType.U8:
case ValueDataType.B8:
case ValueDataType.S8:
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS:
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U24:
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.B64:
case ValueDataType.U64:
case ValueDataType.S16:
case ValueDataType.S32:
case ValueDataType.S64:
case ValueDataType.F32:
case ValueDataType.F64:
case ValueDataType.U32MJK_SN:
{
if (typeof(Double) == value.GetType())
{
valueAsTxt = XmlConvert.ToString((Double)value);
}
else if (typeof(Single) == value.GetType())
{
valueAsTxt = XmlConvert.ToString((Single)value);
}
return valueAsTxt;
}
case ValueDataType.U128:
if (typeof(BigInteger) == value.GetType())
{
valueAsTxt = ((BigInteger)value).ToString("X"); // enclode as hex
}
else
{
throw new Exception($"{value.GetType()} is not supported for U128 xml convert");
}
return valueAsTxt;
//case DeviceValueDataType.U32IPV4: return valueAsTxt.Trim( ).StripIllegalXMLChars( );// handled as a string
default:
if (type.IsText())
{ // Do this as the last check to save CPU power
return valueAsTxt.Trim().StripIllegalXMLChars();
}
throw new NotImplementedException("DataType '" + type + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "EncodeXML()", "dataType = " + type.ToString() + " Value is = " + value.ToString()));
}
}
public static Object DecodeXML(this string valueInXml, ValueDataType type)
{
try
{
switch (type)
{
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC:
return XmlConvert.ToUInt32(valueInXml).Convert1970SecToTime(TimeType.Local);
case ValueDataType.U32TIME_Y2000:
return XmlConvert.ToUInt32(valueInXml).Convert2000SecToTime();
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC: return XmlConvert.ToUInt32( valueInXml );
case ValueDataType.B8:
case ValueDataType.U8:
return XmlConvert.ToByte(valueInXml);
case ValueDataType.S8:
return XmlConvert.ToSByte(valueInXml);
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return XmlConvert.ToUInt16(valueInXml);
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS:
//case DeviceValueDataType.U24:
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
return XmlConvert.ToUInt32(valueInXml);
case ValueDataType.B64:
case ValueDataType.U64: return XmlConvert.ToUInt64(valueInXml);
case ValueDataType.S16: return XmlConvert.ToInt16(valueInXml);
case ValueDataType.S32: return XmlConvert.ToInt32(valueInXml);
case ValueDataType.S64: return XmlConvert.ToInt64(valueInXml);
case ValueDataType.F32: return XmlConvert.ToSingle(valueInXml);
case ValueDataType.F64: return XmlConvert.ToDouble(valueInXml);
case ValueDataType.U128: return BigInteger.Parse(valueInXml, System.Globalization.NumberStyles.HexNumber);
//case DeviceValueDataType.U32IPV4: return valueInXml.ReinsetIllegalXMLChars( );// handled as a string
default:
if (type.IsText())
{ // Do this as the last check to save CPU power
return valueInXml.ReinsetIllegalXMLChars();
}
throw new NotImplementedException("DataType '" + type + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "DecodeXML()", "dataType = " + type.ToString() + " Value is = " + valueInXml));
}
}
/// <summary>
/// do layout changes on byte stream
/// </summary>
/// <param name="bytes"></param>
/// <param name="layout"></param>
/// <returns></returns>
static byte[] DoLayout(this byte[] bytes, LayoutType layout = LayoutType.Normal)
{
try
{
switch (layout)
{
case LayoutType.Normal: return bytes; ; // Do nothing
case LayoutType.SwapAll: return bytes.Reverse();
default:
throw new NotSupportedException(layout + " is not supported");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "DoLayout", "layout = " + layout));
}
}
/// <summary>
/// Encode data with normal data layout
/// </summary>
/// <param name="value"></param>
/// <param name="dataType"></param>
/// <param name="EmailCharacterSet">Null if not used</param>
/// <returns></returns>
public static byte[] Encode(this object value, ValueDataType dataType, GetEmailCharacterSetToUse emailCharacterSet = null)
{
try
{
if (value == null)
{
throw new Exception("Value is null");
}
switch (dataType)
{
case ValueDataType.B8:
case ValueDataType.U8:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(byte));// Try set type if not the correct one
return BitConverter.GetBytes((byte)value);
}
case ValueDataType.S8:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(sbyte));// Try set type if not the correct one
return BitConverter.GetBytes((sbyte)value);
}
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return BitConverter.GetBytes((UInt16)value);
case ValueDataType.U32TIME_Y1970:
if (value is DateTime)
{
return BitConverter.GetBytes(((DateTime)value).ConvertTimeTo1970Sec(TimeType.Local));
}
return BitConverter.GetBytes((UInt32)value); // Work around on olde types
case ValueDataType.U32TIME_Y1970_UTC:
if (value is DateTime)
{
return BitConverter.GetBytes(((DateTime)value).ConvertTimeTo1970Sec(TimeType.UTC));
}
return BitConverter.GetBytes((UInt32)value); // Work around on olde types
case ValueDataType.U32TIME_Y2000:
if (value is DateTime)
{
return BitConverter.GetBytes(((DateTime)value).ConvertTimeTo2000Sec(TimeType.Local));
}
return BitConverter.GetBytes((UInt32)value);
// Work around on olde types
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
// return BitConverter.GetBytes( TimeConvertClass.ToMidnightSecOffsetUTC( (UInt32)value ) );
//case DeviceValueDataType.U24DateHH_MM_SS: {
// var timeSpan = TimeConvertClass.ConvertTimeSpan( (UInt32)value );
// return new byte[] { (byte)timeSpan.Seconds, (byte)timeSpan.Minutes, (byte)timeSpan.Hours };
// }
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: {
// var date = ((UInt32)value).Convert1970SecToTime( TimeType.Local );
// return new byte[] {
// (byte)date.Second,
// (byte)date.Minute,
// (byte)date.Hour,
// (byte)date.Day,
// (byte)date.Month,
// (byte)(date.Year - 2000)
// };
// }
//case DeviceValueDataType.U24: {
// value = CorrectTypeIfNotTheSame( value, dataType, typeof( UInt32 ) );// Try set type if not the correct one
// return BitConverter.GetBytes( (UInt32)value ).Remove( 3 );
// }
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(UInt32));// Try set type if not the correct one
return BitConverter.GetBytes((UInt32)value);
}
case ValueDataType.B64:
case ValueDataType.U64:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(UInt64));// Try set type if not the correct one
return BitConverter.GetBytes((UInt64)value);
}
case ValueDataType.S16:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(Int16));// Try set type if not the correct one
return BitConverter.GetBytes((Int16)value);
}
case ValueDataType.S32:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(Int32));// Try set type if not the correct one
return BitConverter.GetBytes((Int32)value);
}
case ValueDataType.F32:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(Single));// Try set type if not the correct one
return BitConverter.GetBytes((Single)value);
}
case ValueDataType.F64:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(double));// Try set type if not the correct one
return BitConverter.GetBytes((double)value);
}
case ValueDataType.U128:
{
value = CorrectTypeIfNotTheSame(value, dataType, typeof(BigInteger));// Try set type if not the correct one
return ((BigInteger)value).ToByteArray(); // TODO: Is this okay or need always to be the 16 byte in size?
}
//case DeviceValueDataType.U32IPV4: return U32_IP_Encoder.Encode( value.ToString( ) );
default:
if (dataType.IsText())
{ // Do this as the last check to save CPU power
var typeAsText = dataType.ToString();
// is Email
if (dataType.IsEmailText())
{
return StringEncoderEmail.Encode(value.ToString(), Length(dataType), ((emailCharacterSet == null) ? "" : emailCharacterSet()));
}
// is SMS
if (dataType.IsSMSText())
{
return StringEncoderUnicode.Encode(value.ToString(), Length(dataType));
}
// is Windows 1252
if (dataType.IsWindows1252Text())
{
return StringEncoder_W1252.Encode(value.ToString(), Length(dataType));
}
// is Windows 1252, but needs to have "<>" in frond and end
// Ex. end result is "<tmo@xyleminc.com>,<tmo@mjk.dk>" or "<tmo@xyleminc.com>"
if (dataType.IsWindows1252TextRecipient())
{
var valueAsText = value.ToString().Trim();
if (!String.IsNullOrEmpty(valueAsText))
{
// Remove manual added brackets or " if user has done it in the past
if (valueAsText.Contains("\""))
{
valueAsText = valueAsText.Replace("\"", "");
}
//// work arround if user has already used "," as separation
//if (valueAsText.Contains( "," )) {
// valueAsText = valueAsText.Replace( ",", ">,<" ); //old modem firmware V1.003 and TDC NO
//}
// Replace ";" with correct "," as separation and add bracked ">" "<" to support RCF821
if (valueAsText.Contains(";"))
{
//valueAsText = valueAsText.Replace( ";", ">,<" ); old modem firmware V1.003 and TDC NO
valueAsText = valueAsText.Replace(";", ",");//new modem firmware V1.3 using mail.mjk-link.dk
}
// Trim
valueAsText = valueAsText.Trim();
// Add brackets "<>" around address / addresses and end with " to tell modem where it starts and end in MC55I at command
//Ex. end result is "<tmo@xyleminc.com>,<tmo@mjk.dk>" or "<tmo@xyleminc.com>"
if (!String.IsNullOrEmpty(valueAsText))
{
//valueAsText = "\"<" + valueAsText + "\">"; old modem firmware V1.003 and TDC NO
valueAsText = "\"" + valueAsText + "\""; //new modem firmware V1.3 using mail.mjk-link.dk
}
}
return StringEncoder_W1252.Encode(valueAsText, Length(dataType));
}
// is Quoted Printable Text
if (dataType.IsEmailQuotedPrintableText())
{
return StringEncoderEmail_Q_Types.Encode(value.ToString(), Length(dataType), ((emailCharacterSet == null) ? "" : emailCharacterSet()));
}
// Is is normal utf8
return StringEncoder.Encode(value.ToString(), Length(dataType));
}
throw new NotImplementedException("DataType '" + dataType + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Encode", "dataType = " + dataType.ToString()));
}
}
private static object CorrectTypeIfNotTheSame(object value, ValueDataType correctTypeTag, Type typeUsedForCast)
{
try
{
if (value.GetType() == typeUsedForCast)
{
return value; // Nothing to change
}
{
AppConst.Logger.AddFuncLog(
#if DEBUG //
true // log as error
#else
false // Log silent in log
#endif //#if DEBUG
, typeof(DeviceValueEncoder).ToString(), "CorrectTypeIfNotTheSame()",
"Warning! correction was needed. Is this a older setting else not okay? " + MakeCorrectTypeValueInfoText(value, correctTypeTag, typeUsedForCast)
);
}
return ToValue(value.ToString(), correctTypeTag);
}
catch (Exception ex)
{
var valueInfo = MakeCorrectTypeValueInfoText(value, correctTypeTag, typeUsedForCast);
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "CorrectTypeIfNotTheSame", valueInfo));
}
}
/// <summary>
/// Generate the value info possible to get for a value to convert
/// </summary>
/// <param name="value">Value to correct</param>
/// <param name="correctTypeTag">correct value type tag</param>
/// <param name="typeUsedForCast">type used for cast</param>
/// <returns>Text to show in log</returns>
private static string MakeCorrectTypeValueInfoText(object value, ValueDataType correctTypeTag, Type typeUsedForCast)
{
var ValueInfo = "";
try
{
if (ValueInfo == null)
{
ValueInfo += " Value= IS NULL and not possible to correct!";
}
else
{
ValueInfo += " Value=\"" + value.ToString() + "\"";
ValueInfo += " From Type=\"" + value.GetType() + "\"";
}
ValueInfo += " To Type=\"" + correctTypeTag.ToString() + "\"";
}
catch { ValueInfo += " [Fail to get info ?] "; }
return ValueInfo;
}
/// <summary>
/// Encode data with data layout setting
/// </summary>
/// <param name="value"></param>
/// <param name="dataType"></param>
/// <param name="layout"></param>
/// <param name="emailCharacterSet">Null if not used</param>
/// <returns></returns>
public static byte[] Encode(this object value, ValueDataType dataType, LayoutType layout, GetEmailCharacterSetToUse emailCharacterSet = null)
{
try
{
var bytes = Encode(value, dataType, emailCharacterSet);
if (bytes == null)
{
return bytes;
}
return bytes.DoLayout(layout);
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Encode", "dataType = " + dataType.ToString()));
}
}
/// <summary>
/// Decode data with normal data layout
/// </summary>
/// <param name="value"></param>
/// <param name="dataType"></param>
/// <param name="emailCharacterSet">Null if not used</param>
/// <returns></returns>
public static object Decode(this byte[] value, ValueDataType dataType, GetEmailCharacterSetToUse emailCharacterSet = null)
{
try
{
if (value == null)
{
throw new Exception("Value is null");
}
if (value.Count() == 0)
{
throw new Exception("Value Has no values in array");
}
switch (dataType)
{
case ValueDataType.B8:
case ValueDataType.U8:
return (byte)value.First();
case ValueDataType.S8:
return (sbyte)value.First();
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return BitConverter.ToUInt16(value, 0);
case ValueDataType.U32TIME_Y1970:
return BitConverter.ToUInt32(value, 0).Convert1970SecToTime(TimeType.Local);
case ValueDataType.U32TIME_Y1970_UTC:
return BitConverter.ToUInt32(value, 0).Convert1970SecToTime(TimeType.UTC).ToLocalTime();
case ValueDataType.U32TIME_Y2000:
return BitConverter.ToUInt32(value, 0).Convert2000SecToTime();
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
// return TimeConvertClass.FromMidnightSecOffsetUTC( BitConverter.ToUInt32( value, 0 ) );
//case DeviceValueDataType.U24DateHH_MM_SS: {
// return (UInt32)((UInt32)value[ 2 ] * 3600) + ((UInt32)value[ 1 ] * 60 + (UInt32)value[ 0 ]);
// }
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: {
// var date = new DateTime( (int)value[ 5 ] + 2000, value[ 4 ], value[ 3 ], value[ 2 ], value[ 1 ], value[ 0 ] );
// return date.ConvertTimeTo1970Sec( TimeType.Local );
// }
//case DeviceValueDataType.U24: {
// var as32bitValue = new byte[] { value[ 0 ], value[ 1 ], value[ 2 ], 0 };
// return BitConverter.ToUInt32( as32bitValue, 0 );
// }
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
return BitConverter.ToUInt32(value, 0);
case ValueDataType.B64:
case ValueDataType.U64: return BitConverter.ToUInt64(value, 0);
case ValueDataType.S16: return BitConverter.ToInt16(value, 0);
case ValueDataType.S32: return BitConverter.ToInt32(value, 0);
case ValueDataType.F32: return BitConverter.ToSingle(value, 0);
case ValueDataType.F64: return BitConverter.ToDouble(value, 0);
case ValueDataType.U128:
{
// Need a zero in msb to avoid value is handled as signed
var valueConverted = new BigInteger((value).Concat(new byte[1]).ToArray());
return valueConverted;
}
case ValueDataType.Array6B:
case ValueDataType.Array10B:
case ValueDataType.Array12B:
case ValueDataType.Array64B:
case ValueDataType.Array128B:
case ValueDataType.Array136B:
case ValueDataType.Array250B: return value;
//case DeviceValueDataType.U32IPV4: return U32_IP_Encoder.Decode( value );
default:
if (dataType.IsText())
{ // Do this as the last check to save CPU power
var typeAsText = dataType.ToString();
if (dataType.IsEmailText())
{ // is Email
return StringEncoderEmail.Decode(value, Length(dataType), ((emailCharacterSet == null) ? "" : emailCharacterSet()));
}
if (dataType.IsSMSText())
{ // is SMS
return StringEncoderUnicode.Decode(value, Length(dataType));
}
if (dataType.IsWindows1252Text())
{ // is Windows 1252
return StringEncoder_W1252.Decode(value, Length(dataType));
}
if (dataType.IsWindows1252TextRecipient())
{ // is Windows 1252, but needs to have "<>" in frond and end
var valueAsText = StringEncoder_W1252.Decode(value, Length(dataType));
if (!String.IsNullOrEmpty(valueAsText))
{
// Remove added brackets or " nessesarry that is only to be
// Ex. end result is "<tmo@xyleminc.com>,<tmo@mjk.dk>" or "<tmo@xyleminc.com>"
if (valueAsText.Contains("\""))
{
valueAsText = valueAsText.Replace("\"", "");
}
if (valueAsText.Contains("<"))
{
valueAsText = valueAsText.Replace("<", "");
}
if (valueAsText.Contains(">"))
{
valueAsText = valueAsText.Replace(">", "");
}
// Replace email seperation and replace it with correct the standard ";"
if (valueAsText.Contains(","))
{
valueAsText = valueAsText.Replace(",", ";");
}
}
return valueAsText;
}
if (dataType.IsEmailQuotedPrintableText())
{
return StringEncoderEmail_Q_Types.Decode(value, Length(dataType), ((emailCharacterSet == null) ? "" : emailCharacterSet()));
}
// Is allowed to have a variable length on a string / text
var maxLng = dataType.Length();
if (value.Length > maxLng)
{
throw new Exception(String.Format("Size of text is {0} and more than max {1}", value.Length, maxLng));
}
// Is is normal utf8
return StringEncoder.Decode(value, value.Length);
}
throw new NotImplementedException("DataType '" + dataType + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Decode", "dataType = " + dataType.ToString()));
}
}
/// <summary>
/// Decode data with data layout setting
/// </summary>
/// <param name="value"></param>
/// <param name="dataType"></param>
/// <param name="emailCharacterSet">Null if not used</param>
/// <param name="layout"></param>
/// <returns></returns>
public static object Decode(this byte[] value, ValueDataType dataType, LayoutType layout, GetEmailCharacterSetToUse emailCharacterSet = null)
{
try
{
var bytes = value.DoLayout(layout);
return Decode(value, dataType, emailCharacterSet);
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Encode", "dataType = " + dataType.ToString()));
}
}
/// <summary>
/// Convert a local defined string value to the correct value object according to dataType ("DeviceValueType")
/// </summary>
/// <param name="value">Value as string (floating point must use local setting for "," or ".") and DateTime as local time </param>
/// <param name="dataType"></param>
/// <returns></returns>
public static object ToValue(this string value, ValueDataType dataType)
{
try
{
if (value == null)
{
throw new Exception("Value is null");
}
switch (dataType)
{
case ValueDataType.B8:
case ValueDataType.U8:
return (byte)Convert.ToUInt16(value);
case ValueDataType.S8:
return (sbyte)Convert.ToInt16(value);
case ValueDataType.B16:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
return Convert.ToUInt16(value);
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC:
case ValueDataType.U32TIME_Y2000:
// Always expect this as local time
return new DateTime(Convert.ToDateTime(value).Ticks, DateTimeKind.Local);
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U24:
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
return Convert.ToUInt32(value);
case ValueDataType.B64:
case ValueDataType.U64: return Convert.ToUInt64(value);
case ValueDataType.S16: return Convert.ToInt16(value);
case ValueDataType.S32: return Convert.ToInt32(value);
case ValueDataType.F32: return Convert.ToSingle(value);
case ValueDataType.F64: return Convert.ToDouble(value);
case ValueDataType.U128:
// Need a zero in msb to avoid value is handled as signed
return BigInteger.Parse("0"+value, System.Globalization.NumberStyles.HexNumber);
//case DeviceValueDataType.U32IPV4: {
// if (dataType.IsText( )) {
// return value.ToString( );
// }
// throw new NotImplementedException( "DataType '" + dataType + "' not recognized." );
// }
default:
if (dataType.IsText())
{ // Do this as the last check to save CPU power
var typeAsText = dataType.ToString();
if (dataType.IsEmailText())
{ // is Email
return value;
}
if (dataType.IsSMSText())
{ // is SMS
return value;
}
if (dataType.IsWindows1252Text())
{ // is Windows 1252
return value;
}
if (dataType.IsWindows1252TextRecipient())
{ // is Windows 1252, but needs to have "<>" in frond and end
return value;
}
if (dataType.IsEmailQuotedPrintableText())
{ // is Special Email Quoted Printable
return value;
}
// Is is normal utf8
return value; //TODO: No converting is done. may have to be converted to utf8?
}
throw new NotImplementedException("DataType '" + dataType + "' not recognized.");
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "ToValue()", "dataType = " + dataType.ToString()));
}
}
/// <summary>
/// Return data Byte Length (1x8bit)
/// </summary>
/// <returns></returns>
public static int Length(this ValueDataType DataType)
{
try
{
switch (DataType)
{
case ValueDataType._Empty: return 0;
#region ---- 8 Bit ----
case ValueDataType.Bool:
case ValueDataType.B8:
case ValueDataType.S8:
case ValueDataType.U8: return 1;
#endregion // #region ---- 8 Bit ----
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U24: return 3;
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: return 6;
default:
return WLength(DataType) << 1;
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "Length"));
}
}
/// <summary>
/// Return data Word Length (2x8bit)
/// </summary>
/// <returns></returns>
public static int WLength(this ValueDataType DataType)
{
try
{
switch (DataType)
{
case ValueDataType._Empty: return 0;
#region ---- 8 / 16 Bit ----
case ValueDataType.Bool:
case ValueDataType.B8:
case ValueDataType.S8:
case ValueDataType.U8:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
case ValueDataType.B16:
case ValueDataType.S16:
case ValueDataType.U16TEXTID:
case ValueDataType.U16UNIT:
case ValueDataType.U16UNITGROUP: return 1;
#endregion
//case DeviceValueDataType.U48DateYY_MM_DD_HH_MM_SS: return 3;
//case DeviceValueDataType.U24DateHH_MM_SS:
//case DeviceValueDataType.U24: return 2;
#region ---- 32 Bit ----
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
case ValueDataType.S32:
case ValueDataType.F32:
//case DeviceValueDataType.U32TIMESPAN_MIDNIGHT_UTC:
case ValueDataType.U32TIME_Y2000:
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC:
//case DeviceValueDataType.U32IPV4:
return 2;
#endregion
#region ---- 12 x 8 Bit Time Types ----
case ValueDataType.TIME_ASCII_12B:
case ValueDataType.TIME_ymdhms:
return 6;
#endregion
#region ---- 64 Bit ----
case ValueDataType.B64:
case ValueDataType.U64:
case ValueDataType.S64:
case ValueDataType.F64:
return 4;
#endregion
#region ---- 128 Bit ----
case ValueDataType.U128:
return 8;
#endregion
#region ---- Bit Arrays ----
case ValueDataType.Array6B: return (6 / 2);
case ValueDataType.Array10B: return (10 / 2);
case ValueDataType.Array12B: return (12 / 2);
case ValueDataType.Array64B: return (64 / 2);
case ValueDataType.Array128B: return (128 / 2);
case ValueDataType.Array136B: return (136 / 2);
case ValueDataType.Array250B: return (250 / 2);
#endregion
#region ---- Strings / Text ----
//6bytes
case ValueDataType.STR6E:
case ValueDataType.STR6S:
//case DeviceValueDataType.STR6Q:
//case DeviceValueDataType.STR6W1252:
case ValueDataType.STR6: return 3;
//8bytes
case ValueDataType.STR8E:
case ValueDataType.STR8S:
//case DeviceValueDataType.STR8Q:
//case DeviceValueDataType.STR8W1252:
case ValueDataType.STR8: return 4;
//10bytes
case ValueDataType.STR10E:
case ValueDataType.STR10S:
//case DeviceValueDataType.STR10Q:
//case DeviceValueDataType.STR10W1252:
case ValueDataType.STR10: return 5;
//16bytes
case ValueDataType.STR16E:
case ValueDataType.STR16S:
//case DeviceValueDataType.STR16Q:
//case DeviceValueDataType.STR16W1252:
case ValueDataType.STR16: return 8;
//18bytes
case ValueDataType.STR18E:
case ValueDataType.STR18S:
//case DeviceValueDataType.STR18Q:
//case DeviceValueDataType.STR18W1252:
case ValueDataType.STR18: return 9;
//20bytes
case ValueDataType.STR20E:
case ValueDataType.STR20S:
//case DeviceValueDataType.STR20Q:
//case DeviceValueDataType.STR20W1252:
case ValueDataType.STR20: return 10;
//22bytes
case ValueDataType.STR22E:
case ValueDataType.STR22S:
//case DeviceValueDataType.STR22Q:
//case DeviceValueDataType.STR22W1252:
case ValueDataType.STR22: return 11;
//30bytes
case ValueDataType.STR30E:
case ValueDataType.STR30S:
//case DeviceValueDataType.STR30Q:
//case DeviceValueDataType.STR30W1252:
case ValueDataType.STR30: return 15;
//32bytes
case ValueDataType.STR32E:
case ValueDataType.STR32S:
//case DeviceValueDataType.STR32Q:
//case DeviceValueDataType.STR32W1252:
case ValueDataType.STR32: return 16;
//64bytes
case ValueDataType.STR64E:
case ValueDataType.STR64S:
//case DeviceValueDataType.STR64Q:
//case DeviceValueDataType.STR64W1252:
case ValueDataType.STR64: return 32;
//100bytes
case ValueDataType.STR100E:
case ValueDataType.STR100S:
//case DeviceValueDataType.STR100Q:
//case DeviceValueDataType.STR100W1252:
case ValueDataType.STR100: return 50;
//128bytes
case ValueDataType.STR128E:
case ValueDataType.STR128S:
//case DeviceValueDataType.STR128Q:
//case DeviceValueDataType.STR128W1252:
//case DeviceValueDataType.STR128W1252rec:
case ValueDataType.STR128: return 64;
//160bytes
//case DeviceValueDataType.STR160E:
//case DeviceValueDataType.STR160S:
//case DeviceValueDataType.STR160Q:
//case DeviceValueDataType.STR160W1252:
//case DeviceValueDataType.STR160: return 80;
//240bytes
case ValueDataType.STR240E:
case ValueDataType.STR240S:
//case DeviceValueDataType.STR240Q:
//case DeviceValueDataType.STR240W1252:
case ValueDataType.STR240: return 240;
#endregion
default:
throw (new Exception("No known length for tag = " + DataType.ToString()));
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "WLength"));
}
}
/// <summary>
/// Return the text length for value type if it is a text
/// </summary>
/// <returns></returns>
public static int StringLength(this ValueDataType DataType)
{
try
{
switch (DataType)
{
//case DeviceValueDataType.U32IPV4: return (4 * 3 + 3);
default:
if (DataType.IsSMSText())
{ // is SMS
return DataType.Length() / 2; // is always 16bit
}
return Length(DataType);
}
}
catch (Exception ex)
{
throw new Exception(ex.ToFuncErrorText(typeof(DeviceValueEncoder).ToString(), "StringLength"));
}
}
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Communication.ValueEncoders {
public enum LayoutType {
Normal,
SwapAll,
}
}

View File

@ -0,0 +1,92 @@
using System;
using System.Text;
using XYLEM.Communication;
namespace XYLEM.Communication.ValueEncoders {
public static class StringEncoder {
public static Encoding GetDefaultEncoding( ) {
try {
return Encoding.GetEncoding( "Windows-1252"/*Strings._CONFIG_STD_String_DefaultCharacterEncoding*/ );
} catch (Exception ex) {
throw new Exception( typeof( StringEncoder ).ToString( )+ "\n\rGetDefaultEncoding"+ "\n\rError when making default encoding with = "+ "\n\rWindows-1252"/*Strings._CONFIG_STD_String_DefaultCharacterEncoding*/, ex );
}
//Legacy code return Encoding.GetEncoding( 1252 );
}
/// <summary>
/// Standard Windows iso-8859-1-encoding page.
/// </summary>
static Encoding s_Encoder = GetDefaultEncoding( ); // Default Fallback
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <param name="CharacterSet">ex. "iso-8859-1"</param>
/// <returns></returns>
public static byte[] Encode(string value, int lenght, string CharacterSet) {
if (value.Length > lenght) {
throw new ArgumentException( "value.Length is too long", "value" );
}
var result = new byte[ lenght ];
try {
if (!String.IsNullOrEmpty( CharacterSet )) {
Encoding.GetEncoding( CharacterSet ).GetBytes( value ).CopyTo( result, 0 );
return result;
}
} catch (Exception ex) {
throw new Exception( typeof( StringEncoder ).ToString( )+ "\n\rEncode"+ "\n\rWith = " + "iso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/ + Environment.NewLine + ex.Message );
}
// Use defalt
s_Encoder.GetBytes( value ).CopyTo( result, 0 );
return result;
}
/// <summary>
/// Use default characterSet
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <returns></returns>
public static byte[] Encode(string value, int lenght) { return Encode( value, lenght, null ); }
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <param name="CharacterSet">ex. "iso-8859-1"</param>
/// <returns></returns>
public static string Decode(byte[] value, int lenght, string CharacterSet) {
if (value.Length != lenght) {
throw new ArgumentException( "value.Length wrong lenght", "value" );
}
string result = null;
try {
if (!String.IsNullOrEmpty( CharacterSet )) {
result = Encoding.GetEncoding( CharacterSet ).GetString( value );
}
} catch (Exception ex) {
throw new Exception( typeof( StringEncoder ).ToString( )+ "\n\rDecode()"+ "\n\rWith = " + "iso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/ + Environment.NewLine + ex.Message );
}
// Use defalt
if (result == null) {
result = s_Encoder.GetString( value );
}
var index = result.IndexOf( '\0' );
if (index >= 0)
return result.Substring( 0, result.IndexOf( '\0' ) );
else
return result;
}
/// <summary>
/// Use default characterSet
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <returns></returns>
public static string Decode(byte[] value, int lenght) { return Decode( value, lenght, null ); }
}
}

View File

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace XYLEM.Communication.ValueEncoders {
public static class StringEncoderEmail {
public static Encoding GetDefaultEncoding( ) {
try {
return Encoding.GetEncoding( "iso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/ );
} catch (Exception ex) {
throw new Exception( typeof( StringEncoderEmail ).ToString( )+ "\n\rGetDefaultEncoding"+ "\n\rWith = " + "iso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/, ex );
}
// Legacy code return Encoding.GetEncoding( "iso-8859-1" );
}
/// <summary>
/// Standard Windows iso-8859-1-encoding page.
/// </summary>
static Encoding s_Encoder = GetDefaultEncoding( ); // Default Fallback
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <param name="CharacterSet">ex. "iso-8859-1"</param>
/// <returns></returns>
public static byte[] Encode(string value, int lenght, string CharacterSet) {
if (value.Length > lenght) {
throw new ArgumentException( "value.Length is too long", "value" );
}
var result = new byte[ lenght ];
try {
if (!String.IsNullOrEmpty( CharacterSet )) {
Encoding.GetEncoding( CharacterSet ).GetBytes( value ).CopyTo( result, 0 );
return result;
}
} catch (Exception ex) {
throw new Exception( typeof( StringEncoderEmail ).ToString( )+ "\n\rEncode()"+ "\n\rWith = " + "iso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/,ex );
}
// Use defalt
s_Encoder.GetBytes( value ).CopyTo( result, 0 );
return result;
}
/// <summary>
/// Use default characterSet
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <returns></returns>
public static byte[] Encode(string value, int lenght) { return Encode( value, lenght, null ); }
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <param name="CharacterSet">ex. "iso-8859-1"</param>
/// <returns></returns>
public static string Decode(byte[] value, int lenght, string CharacterSet) {
if (value.Length != lenght) {
throw new ArgumentException( "value.Length wrong lenght", "value" );
}
string result = null;
try {
if (!String.IsNullOrEmpty( CharacterSet )) {
result = Encoding.GetEncoding( CharacterSet ).GetString( value );
}
} catch (Exception ex) {
throw new Exception( typeof( StringEncoderEmail ).ToString()+ "\n\rDecode()"+ "\n\rWith = " + "iso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/, ex );
}
// Use defalt
if (result == null) {
result = s_Encoder.GetString( value );
}
var index = result.IndexOf( '\0' );
if (index >= 0) {
return result.Substring( 0, result.IndexOf( '\0' ) );
}
return result;
}
/// <summary>
/// Use default characterSet
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <returns></returns>
public static string Decode(byte[] value, int lenght) { return Decode( value, lenght, null ); }
}
}

View File

@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
namespace XYLEM.Communication.ValueEncoders {
public static class StringEncoderEmail_Q_Types {
static string DefaultEncoding = "iso-8859-1";
public static Encoding GetDefaultEncoding( ) {
try {
return Encoding.GetEncoding( "iso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/ );
} catch (Exception ex) {
throw new Exception( typeof( StringEncoderEmail ).ToString( ) + "\n\rGetDefaultEncoding" + "\n\rError when making default encoding with = " + "iso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/, ex );
}
// Legacy code return Encoding.GetEncoding( DefaultEncoding );
}
#region Converting to Quoted Printable
//http://stackoverflow.com/questions/11793734/code-for-encode-decode-quotedprintable
public static byte[] EncodeQ(byte[] value, int lenght) {
if (value.First( ) == 0) {
return value;
}
List<byte> ret = new List<byte>( );
foreach (byte v in value) {
// The following are not required to be encoded:
// - Tab (ASCII 9)
// - Space (ASCII 32)
// - Characters 33 to 126, except for the equal sign (61).
if ((v == 9) || ((v >= 32) && (v <= 60)) || ((v >= 62) && (v <= 126))) {
if (ret.Count + 1 > lenght) { // Check for length is not over max
break; // Stop converting
}
ret.Add( (byte)Convert.ToChar( v ) );
} else {
if (ret.Count + 3 > lenght) { // Check for length is not over max
break; // Stop converting
}
if (v == 0) {
ret.Add( 0 );
break; // Stop terminate string
}
ret.AddRange( Encoding.UTF8.GetBytes( "=" + v.ToString( "X2" ) ) );
}
}
char lastChar = (char)ret.Last( );
if (char.IsWhiteSpace( lastChar )) {
ret.RemoveAt( ret.Count( ) - 1 );
if (!(ret.Count + 3 > lenght)) { // Check for length is not over max
ret.AddRange( Encoding.UTF8.GetBytes( "=" + ((byte)lastChar).ToString( "X2" ) ) );
}
}
if (ret.Count < lenght) { // Make sure length is correct
ret.AddRange( new byte[ lenght - ret.Count ] );
}
return ret.ToArray( );
}
public static string DecodeQ(byte[] inputBytes, string charSet) {
var input = (new UTF8Encoding( )).GetString( inputBytes );
Encoding enc;
try {
enc = Encoding.GetEncoding( charSet );
} catch {
enc = new UTF8Encoding( );
}
var occurences = new Regex( @"(=[0-9A-Z]{2}){1,}", RegexOptions.Multiline );
var matches = occurences.Matches( input );
foreach (Match match in matches) {
try {
byte[] b = new byte[ match.Groups[ 0 ].Value.Length / 3 ];
for (int i = 0; i < match.Groups[ 0 ].Value.Length / 3; i++) {
b[ i ] = byte.Parse( match.Groups[ 0 ].Value.Substring( i * 3 + 1, 2 ), System.Globalization.NumberStyles.AllowHexSpecifier );
}
char[] hexChar = enc.GetChars( b );
input = input.Replace( match.Groups[ 0 ].Value, new String( hexChar ) );
} catch { ;}
}
input = input.Replace( "?=", "" ).Replace( "\r\n", "" );
return input;
}
#endregion
/// <summary>
/// Standard Windows iso-8859-1-encoding page.
/// </summary>
static Encoding s_Encoder = GetDefaultEncoding( ); // Default Fallback
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <param name="CharacterSet">ex. "iso-8859-1"</param>
/// <returns></returns>
public static byte[] Encode(string value, int lenght, string CharacterSet) {
byte[] ret = null;
if (value.Length > lenght) {
throw new ArgumentException( "value.Length is too long", "value" );
}
var result = new byte[ lenght ];
try {
if (!String.IsNullOrEmpty( CharacterSet )) {
Encoding.GetEncoding( CharacterSet ).GetBytes( value ).CopyTo( result, 0 );
ret = EncodeQ( result, lenght );
}
} catch (Exception ex) {
throw new Exception( typeof( StringEncoderEmail ).ToString( )+ "\n\rEncode()" + "\n\rWith = " + "\n\riso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/, ex );
}
if (ret == null) {
// Use defalt
s_Encoder.GetBytes( value ).CopyTo( result, 0 );
ret = EncodeQ( result, lenght );
}
/*#warning "!!!!!!!!!!!!!!!!! Testing !!!!!!!!!!!!!!!!!!!!!!!"
string test = new UTF8Encoding( ).GetString( ret );*/
return ret;
}
/// <summary>
/// Use default characterSet
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <returns></returns>
public static byte[] Encode(string value, int lenght) { return Encode( value, lenght, null ); }
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <param name="CharacterSet">ex. "iso-8859-1"</param>
/// <returns></returns>
public static string Decode(byte[] value, int lenght, string CharacterSet) {
if (value.Length != lenght) {
throw new ArgumentException( "value.Length wrong lenght", "value" );
}
/*#warning "!!!!!!!!!!!!!!!!! Testing !!!!!!!!!!!!!!!!!!!!!!!"
string test = new UTF8Encoding( ).GetString( value );*/
string result = null;
try {
if (!String.IsNullOrEmpty( CharacterSet )) {
result = DecodeQ( value, CharacterSet );
}
} catch (Exception ex) {
throw new Exception( typeof( StringEncoderEmail ).ToString() + "\n\rDecode()" + "\n\rWith = " + "iso-8859-1"/*Strings._CONFIG_STD_Email_DefaultCharacterEncoding*/, ex );
}
// Use defalt
if (result == null) {
result = DecodeQ( value, DefaultEncoding );
}
var index = result.IndexOf( '\0' );
if (index >= 0) {
return result.Substring( 0, result.IndexOf( '\0' ) );
}
return result;
}
/// <summary>
/// Use default characterSet
/// </summary>
/// <param name="value"></param>
/// <param name="lenght"></param>
/// <returns></returns>
public static string Decode(byte[] value, int lenght) { return Decode( value, lenght, null ); }
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Text;
using XYLEM.Communication;
namespace XYLEM.Communication.ValueEncoders
{
public static class StringEncoderUnicode
{
/// <summary>
/// Standard Windows 1252-encoding page.
/// </summary>
static Encoding s_Unicode = Encoding.BigEndianUnicode;
public static byte[] Encode(string value, int lenght)
{
if (value.Length > lenght)
{
throw new ArgumentException("value.Length is too long", "value");
}
var result = new byte[lenght];
s_Unicode.GetBytes(value).CopyTo(result, 0);
return result;
}
public static string Decode(byte[] value, int lenght)
{
if (value.Length > lenght)
{
throw new ArgumentException("value.Length wrong lenght", "value");
}
var result = s_Unicode.GetString(value);
var index = result.IndexOf('\0');
if (index >= 0)
return result.Substring(0, result.IndexOf('\0'));
else
return result;
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Text;
using XYLEM.Communication;
namespace XYLEM.Communication.ValueEncoders {
public static class StringEncoder_W1252 {
public static Encoding GetDefaultEncoding( ) {
return Encoding.GetEncoding( 1252 );
}
/// <summary>
/// Standard Windows 1252-encoding page.
/// </summary>
static Encoding s_Win1252 = GetDefaultEncoding( );
public static byte[] Encode(string value, int lenght) {
if (value.Length > lenght) {
throw new ArgumentException( "value.Length is too long", "value" );
}
var result = new byte[ lenght ];
s_Win1252.GetBytes( value ).CopyTo( result, 0 );
return result;
}
public static string Decode(byte[] value, int lenght) {
if (value.Length > lenght) {
throw new ArgumentException( "value.Length wrong lenght", "value" );
}
var result = s_Win1252.GetString( value );
var index = result.IndexOf( '\0' );
if (index >= 0)
return result.Substring( 0, result.IndexOf( '\0' ) );
else
return result;
}
}
}

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XYLEM.Base;
namespace XYLEM.Communication.ValueEncoders {
/// <summary>
/// IP Address encoder when it has to be converted to a u32 value
/// </summary>
internal static class U32_IP_Encoder {
/// <summary>
/// Check if string is okay and possible to encode
/// </summary>
/// <param name="stringForCheck"></param>
/// <returns></returns>
internal static bool IsOkay(string stringForCheck) {
try {
if (string.IsNullOrEmpty( stringForCheck )) {
return false; // if string empty, then this is off and there is nothing to check
}
try {
var test = Encode( stringForCheck );
} catch {
return false; // Error is not possible to convert
}
return true; // Okay to convert
} catch (Exception ex) {
throw new Exception( ex.ToFuncErrorText( typeof( U32_IP_Encoder ).ToString( ), "IsOkay" ) );
}
}
/// <summary>
/// Encode xxx.xxx.xxx.xxx to bytes
/// </summary>
/// <param name="ip_XXX_XXX_XXX_XXX"></param>
/// <returns></returns>
static internal byte[] Encode(string ip_XXX_XXX_XXX_XXX) {
try {
var splited = ip_XXX_XXX_XXX_XXX.Split( '.' );
if (splited.Count( ) != 4) {
throw new Exception( "IP must be formated xxx.xxx.xxx.xxx but is " + ip_XXX_XXX_XXX_XXX.ToString( ) );
}
var values = splited.Select( value => byte.Parse( value ) );
return values.ToArray( );
} catch (Exception ex) {
throw new Exception( ex.ToFuncErrorText( typeof( U32_IP_Encoder ).ToString( ), "Encode" ) );
}
}
/// <summary>
/// decode bytes
/// </summary>
/// <param name="data"></param>
/// <returns>xxx.xxx.xxx.xxx</returns>
static internal string Decode(byte[] data) {
try {
if ((data == null) || (data.Count( ) != 4)) {
throw new Exception( "Must be 4 bytes" );
}
return String.Format( "{0}.{1}.{2}.{3}", data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ] );
} catch (Exception ex) {
throw new Exception( ex.ToFuncErrorText( typeof( U32_IP_Encoder ).ToString( ), "Decode" ) );
}
}
}
}

View File

@ -0,0 +1,120 @@
using System;
using System.Xml;
namespace XYLEM.Device
{
/// <summary>
/// A single calibration point
/// </summary>
[Serializable]
public class CalibrationPoint : IComparable<CalibrationPoint>, IEquatable<CalibrationPoint>
{
/// <summary>
/// Reference flow in liter / second
/// https://xyleminc.atlassian.net/wiki/spaces/MJKMF/pages/6661802342
/// </summary>
public Single ReferenceFlowRate_lps { get; set; }
/// <summary>
/// DUT Reported flow in liter / second
/// https://xyleminc.atlassian.net/wiki/spaces/MJKMF/pages/6661802342
/// </summary>
public Single ReportedFlowRate_lps { get; set; }
public CalibrationPoint()
{
ReferenceFlowRate_lps = ReportedFlowRate_lps = 0;
}
/// <summary>
/// Ctor
/// </summary>
/// <param name="referenceFlowRate_lps">reference flow rate [l/s] given by the flow-test-bench</param>
/// <param name="reportedFlowRate_lps">reported flow rate [l/s] by the DUT</param>
public CalibrationPoint(Single referenceFlowRate_lps, Single reportedFlowRate_lps)
{
ReferenceFlowRate_lps = referenceFlowRate_lps;
ReportedFlowRate_lps = reportedFlowRate_lps;
}
public override string ToString()
{
const int w1 = 10;
return $"Ref={ReferenceFlowRate_lps*3.6,w1:F3}m3/h DUT={ReportedFlowRate_lps*3.6,w1:F3}m3/h (Ref={ReferenceFlowRate_lps}L/s DUT={ReportedFlowRate_lps}L/s)";
}
public int CompareTo(CalibrationPoint other)
{
// If null, it can't be the same
if (System.Object.ReferenceEquals(other, null))
{
return -1;
}
// Any of them is not okay
if ((this.ReferenceFlowRate_lps!= other.ReferenceFlowRate_lps) || (this.ReportedFlowRate_lps!= other.ReportedFlowRate_lps))
{
return -1; // Not the same
}
return 0; // is the same
}
public bool Equals(CalibrationPoint other)
{
return this.CompareTo(other) == 0;
}
#region Operator == > < ! ..
public static bool operator ==(CalibrationPoint a, CalibrationPoint b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
// from https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type?redirectedfrom=MSDN
if (a is null)
{
// null == null = true.
if (b is null)
{
return true;
}
// Only the left side is null.
return false;
}
// Return true if the fields match:
return (a.Equals(b));
}
public static bool operator !=(CalibrationPoint a, CalibrationPoint b)
{
return !(a == b);
}
public static bool operator <(CalibrationPoint a, CalibrationPoint b)
{
return a.CompareTo(b) < 0;
}
public static bool operator >(CalibrationPoint a, CalibrationPoint b)
{
return a.CompareTo(b) > 0;
}
public static bool operator >=(CalibrationPoint a, CalibrationPoint b)
{
return a.CompareTo(b) >= 0;
}
public static bool operator <=(CalibrationPoint a, CalibrationPoint b)
{
return a.CompareTo(b) <= 0;
}
#endregion
}
}

View File

@ -0,0 +1,198 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Xml;
using XYLEM.Base.XML;
namespace XYLEM.Device
{
[Serializable]
public class CalibrationPoints : IComparable<CalibrationPoints>, IEquatable<CalibrationPoints>
{
/// <summary>
/// calibrations to or from DUT
/// </summary>
public List<CalibrationPoint> calibrations { get; private set; }
public void SaveToFile(string filePath)
{
XMLWriteFuncClass.WriteToXmlFile(filePath, calibrations, false);
}
/// <summary>
///
/// </summary>
/// <param name="filePath"></param>
/// <returns>Is a valid calibration for DUT</returns>
public bool LoadFromFile(string filePath)
{
var pointsSaved = XMLWriteFuncClass.ReadFromXmlFile<List<CalibrationPoint>>(filePath);
calibrations = pointsSaved;
return IsOkay();
}
/// <summary>
/// Constructor for A empty list of calibrations, to use for loading calibrations from file
/// </summary>
public CalibrationPoints()
{
calibrations = new List<CalibrationPoint>();
}
/// <summary>
///
/// </summary>
/// <param name="cal_points"></param>
/// <param name="maxTotalPoints">Maximum numbers of calibration able to write to device</param>
public CalibrationPoints(List<CalibrationPoint> cal_points, int maxTotalPoints)
{
if (cal_points == null)
{
throw new ArgumentNullException("Calibrations points can't be zero");
}
if (cal_points.Count > maxTotalPoints)
{
throw new Exception($"Has {cal_points.Count} calibrations points and only support {maxTotalPoints}");
}
// Pad with zero if not the full size. Done to make a working writing and comparing two calibrations.
if (cal_points.Count < maxTotalPoints)
{
var missing = maxTotalPoints-cal_points.Count;
cal_points.AddRange(Enumerable.Range(0, missing).Select(_ => new CalibrationPoint(0, 0)));
}
calibrations = cal_points;
}
/// <summary>
/// Is a valid calibration to or from DUT
/// </summary>
/// <returns></returns>
public Boolean IsOkay()
{
if ((null == calibrations) || (0 > calibrations.Count))
{
return false; // Not okay
}
return true; // Is okay
}
/// <summary>
/// Number of calibrations to or from DUT
/// </summary>
/// <returns> is 0 or more if okay and -1 on error / not okay</returns>
public int Get_number_of_calibrations()
{
if (!IsOkay())
{
return -1;
}
return calibrations.Count;
}
public override string ToString()
{
if (!IsOkay())
{
return "No valide calibration to print out";
}
var ret_txt = "";
var idx = 0;
foreach (var cal in calibrations)
{
ret_txt += $"{idx++}: {cal}\n";
}
return ret_txt;
}
public int CompareTo(CalibrationPoints other)
{
// If null, it can't be the same
if (System.Object.ReferenceEquals(other, null))
{
return -1;
}
// Any of them is not okay
if (!this.IsOkay() || !other.IsOkay())
{
return -1; // Not the same
}
// if number of items is not the same
if (this.Get_number_of_calibrations() != other.Get_number_of_calibrations())
{
return -1; // Not the same
}
var num_of_cals = this.calibrations.Count;
var my_cals = this.calibrations;
var others_cals = other.calibrations;
for (int i = 0; i < num_of_cals; i++)
{
if (my_cals[i] != others_cals[i])
{
return -1; // Not the same
}
}
return 0; // is the same
}
public bool Equals(CalibrationPoints other)
{
return this.CompareTo(other) == 0;
}
#region Operator == > < ! ..
public static bool operator ==(CalibrationPoints a, CalibrationPoints b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
// from https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type?redirectedfrom=MSDN
if (a is null)
{
// null == null = true.
if (b is null)
{
return true;
}
// Only the left side is null.
return false;
}
// Return true if the fields match:
return (a.Equals(b));
}
public static bool operator !=(CalibrationPoints a, CalibrationPoints b)
{
return !(a == b);
}
public static bool operator <(CalibrationPoints a, CalibrationPoints b)
{
return a.CompareTo(b) < 0;
}
public static bool operator >(CalibrationPoints a, CalibrationPoints b)
{
return a.CompareTo(b) > 0;
}
public static bool operator >=(CalibrationPoints a, CalibrationPoints b)
{
return a.CompareTo(b) >= 0;
}
public static bool operator <=(CalibrationPoints a, CalibrationPoints b)
{
return a.CompareTo(b) <= 0;
}
#endregion
}
}

View File

@ -0,0 +1,156 @@
using MagFlux6200_metrology_reg_list;
using XYLEM.Communication;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Device
{
/// <summary>
/// Command interface for MagFlux 6200
/// https://xyleminc.atlassian.net/wiki/spaces/MJKMF/pages/7112855120/Command+Interface+Draft
/// </summary>
public interface IMagFluxRequestProtocol
{
/// <summary>
/// Is connected
/// </summary>
/// <returns>true if yes</returns>
Boolean IsConnected();
/// <summary>
/// Make communication connection to Meter
/// !!NOTE!! Only one meter is supported for each com port
/// </summary>
/// <param name="comport">Like "COM1"</param>
/// <returns>true on okay or false on error</returns>
Boolean Connect(string comport);
/// <summary>
/// Close communication connection to Meter
/// </summary>
/// <returns>true on okay or false on error</returns>
Boolean CloseConnection();
/// <summary>
/// Get printout of communication counters
/// </summary>
/// <returns></returns>
string GetComCounters();
/// <summary>
/// Set location for where log data can saved.
/// </summary>
/// <param name="path">path for where to log file should be saved</param>
/// <param name="filename">set a custom log file name without extension (ex. "UserCustomLogFile") or null if use default</param>
/// <returns>true on okay or false on error</returns>
Boolean SetLogLocation(String path, string filename = null);
/// <summary>
/// Open saved log file
/// </summary>
void OpenLogFile();
/// <summary>
/// MagFlux Sensor _serial number
/// </summary>
/// <param name="value_out">a decimal serial number ex. 12345678 or NULL at error</param>
/// <returns>true on okay or false on error</returns>
Boolean GetSensorSerialNo(out string value_out);
/// <summary>
/// Unique-ID for the MagFlux electronics
/// </summary>
/// <param name="value_out">a hex decimal string 0x1234ABCDEF or NULL at error</param>
/// <returns>true on okay or false on error</returns>
Boolean GetUniqueId(out string value_out);
/// <summary>
/// Get the firmware version
/// </summary>
/// <param name="value_out">like 1.2.4 (MAJOR.MINOR.REVISION)</param>
/// <returns>true on okay or false on error</returns>
Boolean GetFirmwareVersion(out string value_out);
/// <summary>
/// Get the firmware build date
/// </summary>
/// <param name="value_out">like 2022/12/24 13:00:00 or 2022-12-24 13:45:10</param>
/// <returns>true on okay or false on error</returns>
Boolean GetFwBuildDate(out string value_out);
/// <summary>
/// Git Hash to Unique identify firmware
/// </summary>
/// <param name="value_out">like 0xABCDE123</param>
/// <returns>true on okay or false on error</returns>
Boolean GetFwGitHash(out string value_out);
/// <summary>
/// Flow rate calibrated
/// </summary>
/// <param name="value_out"> Actual flow rate [l/s] </param>
/// <returns>true on okay or false on error</returns>
Boolean GetFlowRate_lps(out Single value_out);
/// <summary>
/// MagFlux Sensor nominal DN size in millimeters
/// </summary>
/// <param name="value_out">DN size in [mm] is -1 on error</param>
/// <returns>true on okay or false on error</returns>
Boolean GetDn_mm(out Int32 value_out);
/// <summary>
/// Check if there is problem with the DUT
/// use <see cref="GetDeviceErrorMessages"/>" to get a list of error messages for debug problems
/// </summary>
/// <returns>>true if device operates correctly</returns>
Boolean GetDeviceHealthy();
/// <summary>
/// get a list of error messages for debug problem
/// </summary>
/// <param name="status_list_out">Will return a empty list if there is no messages to return</param>
/// <returns>true on okay or false on error</returns>
Boolean GetDeviceErrorMessages(out List<string> status_list_out);
/// <summary>
/// This function prepares the DUT for the calibration.
///
/// ATTENTION:
/// This function needs to be called before the calibration process starts any flow of water.
/// </summary>
/// <returns>true on okay or false on error</returns>
Boolean PrepareDeviceForCalibration();
/// <summary>
/// This function will abort started or failed calibration to bring DUT back to normal calibration state
/// </summary>
/// <returns>true on okay or false on error</returns>
Boolean AbortDeviceForCalibration();
/// <summary>
/// The maximum calibration points that is supported by the device
/// </summary>
int CalibrationPointsMax { get; }
/// <summary>
/// Get list of calibration points saved in DUT
/// </summary>
/// <param name="values_read">The calibrations points from device</param>
/// <returns>true on okay or false on error</returns>
Boolean GetCalibrationPoints(out CalibrationPoints values_read);
/// <summary>
/// set calibration in DUT.
/// Remember to run <see cref="PrepareDeviceForCalibration"/> before the calibration process is started.
/// </summary>
/// <param name="new_calibration_points">A list of calibration points to write to DUT</param>
/// <returns>true on okay or false on error</returns>
Boolean SetCalibrationPoints(CalibrationPoints new_calibration_points);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,319 @@
using MagFlux6200_metrology_reg_list;
using System.Collections.Generic;
using System.Numerics;
using System;
using XYLEM.Communication;
using System.IO.Ports;
using XYLEM.Base.Files;
using System.Threading.Tasks;
using XYLEM.Base;
namespace XYLEM.Device
{
public abstract class ModbusDeviceCom
{
protected ProgramLogCSVFileClass _logger = null;
UInt16 _device_id = 1;
ModbusCom _md_com = null;
#if (!DEBUG)
public Boolean DoComDebugPrint = false;
#else
//public Boolean DoComDebugPrint = true;
public Boolean DoComDebugPrint = false;
#if (DoComDebugPrint)
#warning DoTxValuePrint is true!!!!!!!!!!!!!!!!
#endif
const int ch_lng_dv = -15;
const int ch_lng_Version = -3;
const int ch_lng_MD_adr = -7;
const int dig_value = 10;
#endif
public ModbusDeviceCom()
{
}
public Boolean SetLogLocation(string path, string filename)
{
try
{
// If already created a _logger then
if (_logger != null)
{
// TODO: nothing to do right now
throw new Exception("Logger path can only be set one time");
}
_logger = new ProgramLogCSVFileClass(path, filename);
return true; // Okay
}
catch (Exception ex)
{
Console.WriteLine($"Fail to setup program log path!\nPath:{path}\nMessage:{ex.Message}");
}
return false; // failed
}
public void OpenLogFile()
{
// If already created a _logger then
if (_logger != null)
{
_logger.OpenProgramLogFile();
}
}
public string GetComCounters()
{
if (_md_com == null)
{
return "T=? E=?";
}
return $"T={_md_com.MsgCount} E={_md_com.MsgErrorCount}";
}
public Boolean IsConnected()
{
if (_md_com == null)
{
return false;
}
return _md_com.IsConnected();
}
public Boolean CloseConnection()
{
try
{
StopBackgroundChecking();
if (_md_com != null)
{
/*There is nothing to close right now*/
}
return true; // is okay
}
catch (Exception ex)
{
_logger.AddFuncLog(true, this.ToString(), "CloseConnection", "Fail to close connection", ex);
}
return false; // failed
}
public virtual Boolean Connect(string comport, int baudRate, Parity parity)
{
try
{
{// Normal
if (IsConnected())
{
CloseConnection();
}
_md_com = new ModbusCom(comport, baudRate, parity);
return _md_com.IsConnected(); // return result
}
}
catch (Exception ex)
{
_logger.AddFuncLog(true, this.ToString(), "Connect", "Fail to open connection", ex);
}
return false; // failed
}
#region Background service
System.Timers.Timer _BackgroundCheckingTimer = null;
protected void StartBackgroundChecking()
{
StopBackgroundChecking(); // Make sure that a already running one is stopped
_BackgroundCheckingTimer = new System.Timers.Timer(1000);
_BackgroundCheckingTimer.Elapsed += (sender, e) => HandleBackgroundChecking();
_BackgroundCheckingTimer.Start();
}
protected void StopBackgroundChecking()
{
if (_BackgroundCheckingTimer != null)
{
_BackgroundCheckingTimer.Stop();
_BackgroundCheckingTimer.Close();
_BackgroundCheckingTimer = null;
}
}
/// <summary>
/// Handle checking DUT and background reading device values
/// </summary>
/// <returns></returns>
private void HandleBackgroundChecking()
{
// Don't continue background service before the first has been serviced
if (_BackgroundCheckingTimer != null)
{
_BackgroundCheckingTimer.Stop();
}
try
{
RunBackgroundReadServiceFunction();
}
catch (Exception ex)
{
#if (DEBUG)
var message = $"Fail background service handling";
Console.WriteLine(message);
AppConst.Logger.AddFuncLog(true, this.ToString(), "HandleBackgroundChecking()", message, ex);
#endif // #if (DEBUG)
}
// Don't continue background service before the first has been serviced
if (_BackgroundCheckingTimer != null)
{
_BackgroundCheckingTimer.Start();
}
}
/// <summary>
/// Need to be overwritten with a function for polling periodically read information from device for checking health etc.
/// </summary>
protected abstract void RunBackgroundReadServiceFunction();
#endregion // Background service
#region ---------------- Generic modbus communications ---------------------
protected UInt16? read_U16(Device_value dv)
{
var ret = _md_com.Read(_device_id, dv, new UInt16());
if (ret.IsOkay)
{
var value = ret.Data;
#if (DEBUG)
if (DoComDebugPrint)
{
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,ch_lng_MD_adr} value={value,dig_value}");
}
#endif // #if (DEBUG)
return value;
}
return null; // Error in reading
}
protected UInt32? read_U32(Device_value dv)
{
var ret = _md_com.Read(_device_id, dv, new UInt32());
if (ret.IsOkay)
{
var value = ret.Data;
#if (DEBUG)
if (DoComDebugPrint)
{
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,ch_lng_MD_adr} value={value,dig_value}");
}
#endif // #if (DEBUG)
return value;
}
return null; // Error in reading
}
protected Single? read_F32(Device_value dv)
{
var ret = _md_com.Read(_device_id, dv, new Single());
if (ret.IsOkay)
{
var value = ret.Data;
#if (DEBUG)
if (DoComDebugPrint)
{
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,ch_lng_MD_adr} value={value,dig_value}");
}
#endif // #if (DEBUG)
return value;
}
return null; // Error in reading
}
protected BigInteger? read_U128(Device_value dv)
{
var ret = _md_com.Read(_device_id, dv, new BigInteger());
if (ret.IsOkay)
{
var value = ret.Data;
#if (DEBUG)
if (DoComDebugPrint)
{
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,ch_lng_MD_adr} value={value,dig_value}");
}
#endif // #if (DEBUG)
return value;
}
return null; // Error in reading
}
protected List<ModbusDataRequest> read(List<Device_value> dvList)
{
var ret = _md_com.Read(_device_id, dvList);
if (ret.Count > 0)
{
#if (DEBUG)
foreach (var data in ret)
{
if (DoComDebugPrint)
{
var dv = data.Info;
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,ch_lng_MD_adr} value={data.Data,dig_value}");
}
}
#endif // #if (DEBUG)
return ret;
}
return null; // Error in reading
}
protected bool write_U16(Device_value dv, UInt16 value)
{
var isOkay = _md_com.Write(_device_id, dv, value);
if (!isOkay)
{
#if (DEBUG)
if (DoComDebugPrint)
{
Console.WriteLine($"Failed Write={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,ch_lng_MD_adr} value={value,dig_value}");
}
#endif // #if (DEBUG)
}
return isOkay; // Error in reading
}
/// <summary>
/// Write multiple values in a optimized number of telegrams
/// </summary>
/// <param name="reqList"></param>
/// <returns></returns>
protected List<ModbusDataRequest> write(List<ModbusDataRequest> reqList)
{
var ret = _md_com.Write(_device_id, reqList);
if ((ret!=null) && (ret.Count > 0))
{
#if (DEBUG)
foreach (var data in ret)
{
if (DoComDebugPrint)
{
var dv = data.Info;
Console.WriteLine($"Write={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,ch_lng_MD_adr} value={data.Data,dig_value} {data.IsOkay}");
}
}
#endif // #if (DEBUG)
return ret;
}
return null; // Error in reading
}
#endregion // #region ---------------- Generic modbus communications ---------------------
}
}

View File

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XYLEM.Device.Value
{
/// <summary>
/// Possible Type to use
/// </summary>
public enum ValueDataType
{
_Empty,
B8,
S8,
U8,
Bool,
U16,
U16MJK_SN,
U16MJK_BRAND_ID,
B16,
S16,
B32,
U32,
U32MJK_SN,
S32,
F32,
B64,
U64,
S64,
F64,
U128,
Array6B,
Array10B,
Array12B,
Array64B,
Array128B,
Array136B,
Array250B,
STR6E,
STR6S,
STR6,
STR8E,
STR8S,
STR8,
STR10E,
STR10S,
STR10,
STR16E,
STR16S,
STR16,
STR18E,
STR18S,
STR18,
STR20E,
STR20S,
STR20,
STR22E,
STR22S,
STR22,
STR30E,
STR30S,
STR30,
STR32E,
STR32S,
STR32,
STR34E,
STR40E,
STR40S,
STR40,
STR64E,
STR64S,
STR64,
STR100E,
STR100S,
STR100,
STR128E,
STR128S,
STR128,
STR240E,
STR240S,
STR240,
U16TEXTID,
U16UNIT,
U16UNITGROUP,
U32TIME_Y2000,
U32TIME_Y1970,
U32TIME_Y1970_UTC,
TIME_ymdhms,
TIME_ASCII_12B
}
}

View File

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace XYLEM.Device.Value
{
public static class ValueDescriptionFunc
{
/// <summary>
/// Is data a text
/// </summary>
/// <returns></returns>
public static Boolean IsText(this ValueDataType DataType)
{
switch (DataType)
{
case ValueDataType._Empty:
case ValueDataType.B8:
case ValueDataType.S8:
case ValueDataType.U8:
case ValueDataType.Bool:
case ValueDataType.U16:
case ValueDataType.U16MJK_SN:
case ValueDataType.U16MJK_BRAND_ID:
case ValueDataType.B16:
case ValueDataType.S16:
case ValueDataType.B32:
case ValueDataType.U32:
case ValueDataType.U32MJK_SN:
case ValueDataType.S32:
case ValueDataType.F32:
case ValueDataType.B64:
case ValueDataType.U64:
case ValueDataType.S64:
case ValueDataType.F64:
case ValueDataType.U128:
case ValueDataType.U16TEXTID:
case ValueDataType.U16UNIT:
case ValueDataType.U16UNITGROUP:
case ValueDataType.U32TIME_Y2000:
case ValueDataType.U32TIME_Y1970:
case ValueDataType.U32TIME_Y1970_UTC:
case ValueDataType.TIME_ASCII_12B:
case ValueDataType.TIME_ymdhms:
case ValueDataType.Array6B:
case ValueDataType.Array10B:
case ValueDataType.Array12B:
case ValueDataType.Array64B:
case ValueDataType.Array128B:
case ValueDataType.Array136B:
case ValueDataType.Array250B:
return false;
default:
if (DataType.ToString().StartsWith("STR"))
{
return true; // Is text
}
throw (new Exception("No known tag = " + DataType.ToString()));
}
}
public static bool IsSMSText(this ValueDataType DataType)
{
if (DataType.IsText())
{
var typeAsText = DataType.ToString();
if (typeAsText.EndsWith("S"))
{ // is Email
return true;
}
}
return false;
}
public static bool IsEmailText(this ValueDataType DataType)
{
if (DataType.IsText())
{
var typeAsText = DataType.ToString();
if (typeAsText.EndsWith("E"))
{ // is Email
return true;
}
}
return false;
}
/// <summary>
/// Conversion has to be for string Quoted Printable Text
/// </summary>
/// <param name="DataType"></param>
/// <returns></returns>
public static bool IsEmailQuotedPrintableText(this ValueDataType DataType)
{
if (DataType.IsText())
{
var typeAsText = DataType.ToString();
if (typeAsText.EndsWith("Q"))
{ // is Email
return true;
}
}
return false;
}
/// <summary>
/// Conversion type for string is Windows 1252
/// </summary>
/// <param name="DataType"></param>
/// <returns></returns>
public static bool IsWindows1252Text(this ValueDataType DataType)
{
if (DataType.IsText())
{
var typeAsText = DataType.ToString();
if (typeAsText.EndsWith("W1252"))
{ // is Email
return true;
}
}
return false;
}
/// <summary>
/// Conversion type for string is Windows 1252 and for the email recipient address that needs special handling
/// Needs to have "<>" in frond and end
/// </summary>
/// <param name="DataType"></param>
/// <returns></returns>
public static bool IsWindows1252TextRecipient(this ValueDataType DataType)
{
if (DataType.IsText())
{
var typeAsText = DataType.ToString();
if (typeAsText.EndsWith("W1252rec"))
{ // is Email
return true;
}
}
return false;
}
}
}

View File

@ -0,0 +1,155 @@
using XYLEM.Device.Value;
using MagFlux6200_metrology_reg_list;
using XYLEM.Communication;
using System;
using System.IO.Ports;
using System.Threading.Tasks;
namespace XYLEM.Device
{
public enum MD_Reg_list
{
APP,
MET
}
public class md_test
{
#region Access data from normal Application RS485
internal static readonly Device_value App_F32FlowRate_m3ps = new Device_value("App_F32FlowRate_m3ps", 600, ValueDataType.F32, ValueRW_Type.ReadOnly, "App read flow");
#endregion
const int ch_lng_dv = -15;
const int ch_lng_Version = -3;
const int ch_lng_MD_adr = -7;
const int dig_value = 10;
public void Go(MD_Reg_list md_reg_list_selection, string serial_port, int baudRate, Parity parity)
{
ModbusCom md = new ModbusCom(serial_port, baudRate, parity);
ReadTests(md_reg_list_selection, md);
}
public void ReadTests(MD_Reg_list md_reg_list_selection, ModbusCom md)
{
var device_id = 1;
//{ // Testing read of specific registers
// var test_rw_items = new[] { reg_list.Met_U32MdbsRegsVer, reg_list.Met_U16DeviceType, reg_list.Met_U32DeviceTypeDetail };
// foreach (var testRead in test_rw_items)
// {// Testing
// Device_value dv = null;
// if (md_reg_list_selection == MD_Reg_list.MET) // Metrology
// {
// dv = testRead;
// var ret = md.Read(device_id, dv, new UInt32());
// if (ret.IsOkay)
// {
// var value = ret.Data;
// Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,-7} value={value,dig_value}");
// }
// }
// else // To application
// {
// dv = null; // Not yet supported
// }
// }
// return;
//}
{ // Read ID
Device_value dv = reg_list.Met_U16DeviceType;
var ret = md.Read(device_id, dv, new UInt16());
if (ret.IsOkay)
{
var value = ret.Data;
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,ch_lng_MD_adr} value={value,dig_value}");
}
}
{// Read Met_U32MdbsRegsVer
Device_value dv = null;
if (md_reg_list_selection == MD_Reg_list.MET) // Metrology
{
dv = reg_list.Met_U32MdbsRegsVer;
var ret = md.Read(device_id, dv, new UInt32());
if (ret.IsOkay)
{
var value = ret.Data;
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,-7} value={value,dig_value}");
}
}
else // To application
{
dv = null; // Not yet supported
}
}
{// Read flow
Device_value dv = null;
string unit = "m3/h";
Single scale = 1.0f;
if (md_reg_list_selection == MD_Reg_list.MET) // Metrology
{
dv = reg_list.Met_F32FlowRate_lps;
scale = 3.6f; // From l/s to m3/h
}
else // To application
{
dv = App_F32FlowRate_m3ps;
scale = 3600f; // From m3/s to m3/h
}
var ret = md.Read(device_id, dv, new Single());
if (ret.IsOkay)
{
var value = ret.Data;
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,-7} value={(value*scale),dig_value} {unit}");
}
}
{// Read / Write scratch
Device_value dv = null;
string unit = "";
Single scale = 1.0f;
if (md_reg_list_selection == MD_Reg_list.MET) // Metrology
{
dv = reg_list.Met_F32Scratch_F32;
Single value = Single.NaN;
{ // read
var ret = md.Read(device_id, dv, new Single());
if (ret.IsOkay)
{
value = ret.Data;
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,-7} value={(value*scale),dig_value} {unit}");
}
}
{ // write
value += 10;
if (!md.Write(device_id, dv, value))
{
Console.WriteLine($"Write failed={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,-7} value={value,dig_value} {unit}");
}
else
{
Console.WriteLine($"Write={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,-7} value={value,dig_value} {unit}");
}
}
{ // read back
var ret = md.Read(device_id, dv, new Single());
if (ret.IsOkay)
{
value = ret.Data; ;
Console.WriteLine($"Read={dv,ch_lng_dv}: Reg_Ver={dv.Version,ch_lng_Version} Adr={dv.MD_adr,-7} value={(value*scale),dig_value} {unit}");
}
}
}
else // To application
{
dv = null; // Not yet supported
}
}
}
}
}

View File

@ -0,0 +1,785 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using XYLEM.Communication;
using System.Xml.Linq;
using XYLEM.Base;
using XYLEM.Communication.ValueEncoders;
using System.Linq.Expressions;
using System.Threading;
using MagFlux6200_metrology_reg_list;
using XYLEM.Device;
using static modbus_master_csharp.Program;
using System.Diagnostics.Contracts;
using System.Security.Policy;
using System.IO;
using System.Diagnostics;
using System.Xml.Schema;
using System.Net.NetworkInformation;
namespace modbus_master_csharp
{
internal class Program
{
static bool LIVE_RUN = true;
#if (DEBUG)
//static bool LIVE_RUN = false; // overwrite default
static bool LIVE_RUN_DIRECT_MET = false; // Run using RS485 9600,8,E setup as default
//static bool LIVE_RUN_DIRECT_MET = LIVE_RUN & true; // overwrite default to Run using 115200,8,N setup as default
#endif
/*For testing directly to metrology */
static string[] argsDefault1 = new string[] { "TEST", "COM11", "115200", "N" };
/*For metrology RS485 when transparent to metrology*/
static string[] argsDefault2 = new string[] { "SAVE_CAL", "COM2" };
// Having more ports
static string[] argsDefault3 = new string[] { "TEST", "COM2", "COM6" };
/*For metrology RS485 when transparent to metrology*/
static string[] argsDefault4 = new string[] { "LOAD_CAL=\"0_sensor_cal_for_testing.xml\"", "COM2" };
/*For metrology RS485 when transparent to metrology*/
static string[] argsDefault5 = new string[] { "TEST", "COM2" };
#region Reused functions for testing
private static bool GetDeviceHealthy(IMagFluxRequestProtocol dut)
{
var name = nameof(dut.GetDeviceHealthy);
var isOkay = dut.GetDeviceHealthy();
var message = $"{name}: {(isOkay ? "Is okay" : "Has errors")}";
if (!isOkay)
{
if (dut.GetDeviceErrorMessages(out var errorList))
{
Console.WriteLine(message + "\nError List:\n" + errorList.ToSingleString(false));
}
else
{
Console.WriteLine(message);
}
}
return isOkay;
}
private static bool GetCalibrationPoints(IMagFluxRequestProtocol dut, out CalibrationPoints value_out, bool printoutPoints)
{
var name = nameof(dut.GetCalibrationPoints);
var isOkay = dut.GetCalibrationPoints(out value_out);
if (printoutPoints)
{
Console.WriteLine($"{name}: Read points-> {(isOkay ? "\n"+value_out.ToString() : "!Read failed!")}");
}
else
{
Console.WriteLine($"{name}: Reading calibration points {(isOkay ? "Okay" : "!Read failed!")}");
}
return isOkay;
}
private static bool SetCalibrationPoints(IMagFluxRequestProtocol dut, CalibrationPoints new_calibration_points)
{
var isOkay = dut.SetCalibrationPoints(new_calibration_points);
Console.WriteLine($"{nameof(dut.SetCalibrationPoints)}: {(isOkay ? "Okay" : "Failed")}\n{new_calibration_points}");
return isOkay;
}
private static void RunTestCalibrationPoints(IMagFluxRequestProtocol dut, CalibrationPoints new_calibration_points)
{
{ // Write calibrations
var isOkay = SetCalibrationPoints(dut, new_calibration_points);
if (!isOkay)
{
GetDeviceHealthy(dut);
throw new Exception("Failed writing the calibration to device");
}
}
{ // Get calibrations and check it
if (!GetCalibrationPoints(dut, out var value_out, false/*Don't printout*/) || (new_calibration_points != value_out))
{
GetDeviceHealthy(dut);
var msg = $"Failed! Calibration is not the same read as written to device\nWritten:\n{new_calibration_points}\nRead:\n{value_out}";
Console.WriteLine(msg);
throw new Exception(msg);
}
}
}
/// <summary>
/// save and load what is read from device
/// </summary>
/// <param name="dut"></param>
/// <param name="value_out"></param>
private static void SaveCalPointsToTempFolder(IMagFluxRequestProtocol dut, CalibrationPoints value_out)
{
var tempSaveFolder = Environment.GetEnvironmentVariable("USERPROFILE")+@"\Downloads\";
if (dut.GetSensorSerialNo(out var sensorSerial))
{
dut.GetUniqueId(out var id);
var sensor_cal_file = tempSaveFolder+$"{sensorSerial}_sensor_cal_id_{id}_{DateTime.Now.ToFileTimeTxt()}.xml";
Console.WriteLine($"Save to:\n{sensor_cal_file}");
value_out.SaveToFile(sensor_cal_file);
// Check saved data
var to_saved_points = value_out.calibrations.ToArray();
value_out.LoadFromFile(sensor_cal_file);
var loaded_points = value_out.calibrations.ToArray();
if (!to_saved_points.SequenceEqual(loaded_points))
{
var msg = $"Failed save of calibrations\nSaved:\n{to_saved_points}\nLoaded:\n{loaded_points}";
Console.WriteLine(msg);
throw new Exception(msg);
}
}
}
private static void SAVE_CAL(List<IMagFluxRequestProtocol> duts)
{
{ // Check Save all calibrations one DUT at a time
for (var dutIdx = 0; dutIdx < duts.Count(); dutIdx++)
{
var dut = duts[dutIdx];
Console.WriteLine($"------------------- DUT{dutIdx+1} --------------------");
try
{
if (!GetCalibrationPoints(dut, out var value_out, true/*printout points*/))
{
GetDeviceHealthy(dut);
throw new Exception("Failed saving device calibration");
}
else
{
// save and load what is read from device
SaveCalPointsToTempFolder(dut, value_out);
}
}
catch (Exception ex)
{
dut.OpenLogFile();
throw ex;
}
}
}
}
/// <summary>
/// Load Calibrations
/// </summary>
/// <param name="duts"></param>
/// <param name="loadedCalibrations"></param>
private static void LOAD_CAL(List<IMagFluxRequestProtocol> duts, List<CalibrationPoints> loadedCalibrations)
{
{ // Check all Values one by one a DUT at a time
if (duts.Count() != loadedCalibrations.Count())
{
throw new Exception("The number of calibrations is not the same as DUT's to load it in");
}
Console.WriteLine("\nSave Calibrations before starting writing new calibrations\n");
SAVE_CAL(duts);
Console.WriteLine("\nStarting writing new calibrations\n");
for (var dutIdx = 0; dutIdx < duts.Count(); dutIdx++)
{
var dut = duts[dutIdx];
Console.WriteLine($"------------------- DUT{dutIdx+1} --------------------");
try
{
var new_calibration_points = loadedCalibrations[dutIdx];
var isOkay = SetCalibrationPoints(dut, new_calibration_points);
if (!isOkay)
{
throw new Exception($"Writing calibration Fail!\n{new_calibration_points}");
}
}
catch (Exception ex)
{
dut.OpenLogFile();
throw ex;
}
}
}
}
static void TEST(List<IMagFluxRequestProtocol> duts)
{
{ // Check all Values one by one a DUT at a time
for (var dutIdx = 0; dutIdx < duts.Count(); dutIdx++)
{
Console.WriteLine($"------------------- DUT{dutIdx+1} --------------------");
var dut = duts[dutIdx];
try
{
//if (false) // Don't do basic reads
if (true) // Do basic read test
{
{
var name = nameof(dut.GetFwGitHash);
var isOkay = dut.GetFwGitHash(out var value_out);
var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}";
Console.WriteLine(message);
if (!isOkay)
{
throw new Exception(message);
}
}
{
var name = nameof(dut.GetSensorSerialNo);
var isOkay = dut.GetSensorSerialNo(out var value_out);
var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}";
Console.WriteLine(message);
if (!isOkay)
{
throw new Exception(message);
}
}
{
var name = nameof(dut.GetUniqueId);
var isOkay = dut.GetUniqueId(out var value_out);
var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}";
Console.WriteLine(message);
if (!isOkay)
{
throw new Exception(message);
}
}
{
var name = nameof(dut.GetFirmwareVersion);
var isOkay = dut.GetFirmwareVersion(out var value_out);
var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}";
Console.WriteLine(message);
if (!isOkay)
{
throw new Exception(message);
}
}
{
var name = nameof(dut.GetFwBuildDate);
var isOkay = dut.GetFwBuildDate(out var value_out);
var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}";
Console.WriteLine(message);
if (!isOkay)
{
throw new Exception(message);
}
}
{
var name = nameof(dut.GetFlowRate_lps);
var isOkay = dut.GetFlowRate_lps(out var value_out);
var message = $"{name}: {(isOkay ? $"{value_out} l/s or {value_out*3.6} m3/h" : "!Read failed!")}";
Console.WriteLine(message);
if (!isOkay)
{
throw new Exception(message);
}
}
{
var name = nameof(dut.GetDn_mm);
var isOkay = dut.GetDn_mm(out var value_out);
var message = $"{name}: {(isOkay ? $"{value_out}mm" : "!Read failed!")}";
Console.WriteLine(message);
if (!isOkay)
{
throw new Exception(message);
}
}
{
GetDeviceHealthy(dut);
}
{
var name = nameof(dut.GetDeviceErrorMessages);
var isOkay = dut.GetDeviceErrorMessages(out var value_out);
var message = $"{name}: \n{(isOkay ? String.Join("\n", value_out) : "!Read failed!")}";
Console.WriteLine(message);
if (!isOkay)
{
throw new Exception(message);
}
}
{
var name = nameof(dut.AbortDeviceForCalibration);
var isOkay = dut.AbortDeviceForCalibration();
var message = $"{name}: {(isOkay ? "Done" : "!Abort failed!")}";
Console.WriteLine(message);
if (!isOkay)
{
throw new Exception(message);
}
}
{
if (!GetCalibrationPoints(dut, out var value_out, true/*printout points*/))
{
GetDeviceHealthy(dut);
}
else
{
// save and load what is read from device
SaveCalPointsToTempFolder(dut, value_out);
}
}
}
//if (false) // Do not execute calibration test
if (LIVE_RUN && true) // execute calibration test
{ // A single calibration Test
{ // --- Test setting the device ready for the first measurement used for calibrations ---
{
var isOkay = dut.PrepareDeviceForCalibration();
Console.WriteLine($"{nameof(dut.PrepareDeviceForCalibration)}: {(isOkay ? "Okay" : "Failed")}");
if (!isOkay || !GetCalibrationPoints(dut, out var value_out, true/*printout points*/))
{
GetDeviceHealthy(dut);
throw new Exception("Failed Setting device up for calibration");
}
}
}
{ // --- Do a simple 2 point calibration with zero ---
var new_calibration_points = new CalibrationPoints(
new List<CalibrationPoint> {
new CalibrationPoint(0,0.001f), // 0
new CalibrationPoint(1,1.002f), // 1
new CalibrationPoint(2,2.003f), // 2
},
dut.CalibrationPointsMax // Extend to
);
RunTestCalibrationPoints(dut, new_calibration_points);
}
{ // --- Do a 6 point calibration with negative zero ---
var new_calibration_points = new CalibrationPoints(
new List<CalibrationPoint> {
new CalibrationPoint(0,-0.001f), // 0
new CalibrationPoint(1,1.002f), // 1
new CalibrationPoint(2,2.003f), // 2
new CalibrationPoint(3,3.004f), // 3
new CalibrationPoint(4,4.005f), // 4
new CalibrationPoint(5,5.006f), // 5
},
dut.CalibrationPointsMax // Extend to
);
RunTestCalibrationPoints(dut, new_calibration_points);
// save and load what is read from device
SaveCalPointsToTempFolder(dut, new_calibration_points);
}
{ // --- Do a check of write of calibrations points that is not ordered correct ---
Console.WriteLine($"Test writing calibration in wrong order is failing and Background check service is running");
{
var new_calibration_points = new CalibrationPoints(
new List<CalibrationPoint> {
new CalibrationPoint(0,-0.001f), // 0
new CalibrationPoint(3,3.002f), // 1 Error this an error in order and need to brake calibrations
new CalibrationPoint(2,2.003f), // 2
},
dut.CalibrationPointsMax // Extend to
);
var isOkay = SetCalibrationPoints(dut, new_calibration_points);
if (isOkay)
{
throw new Exception($"Writing calibration in wrong order needs to Fail!\n{new_calibration_points}");
}
int maxWait_s = 5;
while (maxWait_s-- > 0)
{
Console.Write($"\rWait timer out in {maxWait_s}s for getting Device Healthy is returning showing error: ");
if (!dut.GetFlowRate_lps(out var value_out))
{
throw new Exception($"read of flow failed during polling Device Healthy!");
}
if (!GetDeviceHealthy(dut))
{
Console.WriteLine($"\nGot correct replay that is Device healthy is \"false\"");
break; // Exit
}
Task.Delay(1000).GetAwaiter().GetResult();
}
if (maxWait_s <= 0)
{
throw new Exception($"Device Healthy was returning \"false\" when calibration was failing!\n{new_calibration_points}");
}
}
{// Cleanup by returning calibration to default
var isOkay = dut.PrepareDeviceForCalibration();
if (!isOkay)
{
throw new Exception("Failing returning calibration to default!");
}
}
}
}
}
catch (Exception ex)
{
dut.OpenLogFile();
throw ex;
}
}
}
}
#endregion
enum RUN_ACTION
{
UNKNOWN,
TEST,
SAVE_CAL,
LOAD_CAL,
}
/// <summary>
/// For unit testing setup
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
int ret_error = 0; // Is okay
List<IMagFluxRequestProtocol> duts = new List<IMagFluxRequestProtocol>();
try
{
var runMode = RUN_TYPE.Mock;
if (LIVE_RUN)
{
runMode = RUN_TYPE.Normal;
}
// Just for internal testing
#if (DEBUG)
if (args.Length <= 0)
{
if(LIVE_RUN)
{
args = argsDefault5; //metrology RS485 when transparent to metrology
}
else
{
args = argsDefault5; // Run the functional test as mock
}
if (LIVE_RUN_DIRECT_MET)
{
args = argsDefault1; //testing directly to metrology
}
}
#endif
#region Handle if arguments
bool gotArgs = (args.Length >= 1);
List<string> comports = new List<string>();
int? baudrate = null;
Parity? parity = null;
var runtask = RUN_ACTION.UNKNOWN;
var loadedCalibrations = new List<CalibrationPoints>();
var argHelpNeeded = gotArgs ? false : true;
// Use Default connection if nothing is provided by arguments
var arg_offset = 0;
if (args.Length > arg_offset)
{
// What task to do
if (args.Length > arg_offset)
{
if ("-H" == args[arg_offset].ToUpper())
{
argHelpNeeded = true;
}
else if ("TEST" == args[arg_offset].ToUpper())
{
runtask = RUN_ACTION.TEST;
}
else if ("SAVE_CAL" == args[arg_offset].ToUpper())
{
runtask = RUN_ACTION.SAVE_CAL;
}
else if (args[arg_offset].ToUpper().StartsWith("LOAD_CAL="))
{
runtask = RUN_ACTION.LOAD_CAL;
var calFilePath = args[arg_offset].Split('=').Last();
var cal = new CalibrationPoints();
if (!File.Exists(calFilePath) || !cal.LoadFromFile(calFilePath))
{
throw new InvalidDataException($"Error load calibrations from\n {calFilePath}");
}
loadedCalibrations.Add(cal);
}
else
{
throw new NotImplementedException($"Missing support for parameter {args[arg_offset]}");
}
}
arg_offset++;
{ // Parse com port / ports
var exit = false;
while (!exit)
{
if (args.Length > arg_offset)
{
var arg = args[arg_offset].ToUpper();
if ("COM" == arg.Remove(3))
{
comports.Add(arg);
}
else if (comports.Count <= 0)
{
Console.WriteLine($"Com port {arg} not understood.");
argHelpNeeded = true;
exit = true;
}
else
{
exit = true; // No more com to connect to
}
arg_offset++;
}
else
{
exit = true; // No more com to connect to
}
}
}
if (args.Length > arg_offset)
{
var arg = args[arg_offset].ToUpper();
var allowed_baudrate = new string[] { "9600", "19200", "38400", "57600", "115200", "230400" };
if (allowed_baudrate.Contains(arg))
{
baudrate = int.Parse(arg);
}
else
{
Console.WriteLine($"Baud rate {arg} not known.");
baudrate = -1;
argHelpNeeded = true;
}
}
arg_offset++;
if (args.Length > arg_offset)
{
var arg = args[arg_offset].ToUpper();
if (arg == "E")
{
parity = Parity.Even;
}
else if (arg == "N")
{
parity = Parity.None;
}
else if (arg == "O")
{
parity = Parity.Odd;
}
else
{
Console.WriteLine($"Parity {arg} not known.");
parity = Parity.None;
argHelpNeeded = true;
}
}
}
if (argHelpNeeded)
{
var name_exe = System.AppDomain.CurrentDomain.FriendlyName;
var message = $@"
Arglist indicates help needed. See stdout.
Example of from command line:
Save calibrations only include COMx to use standard baudrate and parity setup:
""{name_exe} {argsDefault2.ToSingleString(false)}""
or run functional test for 2 MagFlux
""{name_exe} {argsDefault3.ToSingleString(false)}""
To run functional test and configure both COMx, baudrate, parity. (Used for com directly to Metrology)
""{name_exe} {argsDefault1.ToSingleString(false)}""
To Load calibrations only include COMx to use standard baudrate and parity setup:
""{name_exe} {argsDefault4.ToSingleString(false)}""
";
Console.WriteLine(message);
return; // exit main
}
#endregion
// Set window to max size to better fit content
// Not needed for now! Console.SetWindowSize(Console.LargestWindowWidth, Console.LargestWindowHeight);
#region Setup Communication to dut's
foreach (var comport in comports)
{
if (runMode != RUN_TYPE.Normal)
{
Console.WriteLine($"{new string('!', 50)}\n Warning is in running in {runMode} mode\n{new string('!', 50)}");
}
MagFlux6200 dut = null;
try
{ // Set up on DUT
dut = new MagFlux6200(runMode);
var log_path = Environment.GetEnvironmentVariable("USERPROFILE")+@"\Downloads\";
var isOkay = dut.SetLogLocation(log_path, "logs_"+comport);
Console.WriteLine($"Using program log path:\n{log_path}");
isOkay &=gotArgs;
if (isOkay)
{ // Use standard and just setup as port
if (baudrate == null)
{
isOkay &=dut.Connect(comport);
}
else if ((baudrate != null) && (parity != null))
{
isOkay &=dut.Connect(comport, baudrate.Value, parity.Value);
}
else
{
isOkay = false; // Error in settings
}
}
if (isOkay)
{
duts.Add(dut);
}
else
{
var port = comport;
if (String.IsNullOrEmpty(port))
{
port = "COM ?";
}
throw new Exception($"Fail to setup device for {port}");
}
}
catch (Exception ex)
{
if (dut!=null)
{
dut.OpenLogFile();
}
throw ex;
}
}
#endregion //#region Setup Communication to dut's
switch (runtask)
{
case RUN_ACTION.TEST:
TEST(duts);
break;
case RUN_ACTION.SAVE_CAL:
{
SAVE_CAL(duts);
}
break;
case RUN_ACTION.LOAD_CAL:
{
LOAD_CAL(duts, loadedCalibrations);
}
break;
default:
{
throw new NotImplementedException($"Missing support run mode {runtask}");
}
}
Console.WriteLine("finished functional testing");
// Is set to true when the monitoring values also needs to stop
bool exitMonitoringLoop = false, pauseMonitoringLoop = false, _LastPauseMonitoringLoop = false;
// Start a task for monitoring a key for exit
Console.WriteLine("Press key 'x' exit, 'p' for pause read, 'c' continue read");
Task.Run(() =>
{
ConsoleKeyInfo keyinfo;
do
{
keyinfo = Console.ReadKey();
if (keyinfo.Key == ConsoleKey.P)
{
pauseMonitoringLoop = true;
}
else if (keyinfo.Key == ConsoleKey.C)
{
pauseMonitoringLoop = false;
}
else
{
Console.WriteLine($"\n{keyinfo.Key} was pressed. Press key 'x' exit");
}
}
while (keyinfo.Key != ConsoleKey.X);
exitMonitoringLoop = true;
});
// Just read flow and other values for testing general measurement
int count = 0;
// "Structure of an interpolated string"
// https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated
while (!exitMonitoringLoop)
{
if (!pauseMonitoringLoop)
{
var message = "\r";
var dutNum = 1;
foreach (var dut in duts)
{
{ // Read Flow
var isOkay = dut.GetFlowRate_lps(out var value_out);
if (dutNum > 1)
{
message += " | ";
}
message += $"DUT{dutNum++}: ";
if (!dut.GetDeviceHealthy())
{
message += $"Error:";
if (dut.GetDeviceErrorMessages(out var errorList))
{
message += $"{errorList.ToSingleString(false)} ";
}
else
{
message += $"No Text to display!";
}
}
else
{
const int w = 9;
message += $"{(isOkay ? $"{value_out*3.6,w:F3} m3/h" : $"!Read failed!")} {dut.GetComCounters()}\t";
if (!isOkay)
{
throw new Exception(message);
}
}
}
}
Console.Write(message + $" msg={++count}\t");
}
{ // Print out if paused read
if (_LastPauseMonitoringLoop != pauseMonitoringLoop)
{
_LastPauseMonitoringLoop = pauseMonitoringLoop;
if (pauseMonitoringLoop)
{
Console.Write("\rRead is Paused!\t\t\t\t\t\t\t\t");
}
}
}
}
}
catch (Exception ex)
{
var name_exe = System.AppDomain.CurrentDomain.FriendlyName;
AppConst.Logger.AddFuncLog(true, name_exe, "main()", ex);
AppConst.Logger.OpenProgramLogFile();
ret_error = -1; //https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes
}
finally
{
// Close connection before exit
try
{
if (duts.Count != 0)
{
foreach (var dut in duts)
{
dut.CloseConnection();
}
}
}
catch { }
Environment.Exit(ret_error); //https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes
}
}
}
}

View File

@ -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("modbus_master_csharp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Xylem Inc.")]
[assembly: AssemblyProduct("modbus_master_csharp")]
[assembly: AssemblyCopyright("Copyright © Xylem Inc. 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("f14940f8-3c86-4bb7-a915-b021e4b3052d")]
// 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")]

View File

@ -0,0 +1,89 @@
<?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>{F14940F8-3C86-4BB7-A915-B021E4B3052D}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>XYLEM</RootNamespace>
<AssemblyName>modbus_master_csharp</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<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' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<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.Numerics" />
<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="Base\AppConst.cs" />
<Compile Include="Base\ByteArrayExtensionClass.cs" />
<Compile Include="Base\Convert1970SecToTime.cs" />
<Compile Include="Base\DataUnion.cs" />
<Compile Include="Base\Files\PathTools.cs" />
<Compile Include="Base\Files\ProgramLogCSVFileClass.cs" />
<Compile Include="Base\LogMessageTool.cs" />
<Compile Include="Base\NumberConvert.cs" />
<Compile Include="Base\StringConvert.cs" />
<Compile Include="Base\XML\XMLStringClass.cs" />
<Compile Include="Base\XML\XMLWriteFuncClass.cs" />
<Compile Include="Device\CalibrationPoint.cs" />
<Compile Include="Device\CalibrationPoints.cs" />
<Compile Include="Device\IMagFluxRequestProtocol.cs" />
<Compile Include="Device\MagFlux6200_metrology_reg_list.cs" />
<Compile Include="Device\MagFlux6200.cs" />
<Compile Include="Device\md_test.cs" />
<Compile Include="Communication\DeviceExceptionData.cs" />
<Compile Include="Communication\ModbusCom.cs" />
<Compile Include="Device\ModbusDeviceCom.cs" />
<Compile Include="Device\Value\ValueDataType.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Communication\FuncTypes.cs" />
<Compile Include="Communication\ProtocolTranslateModbusRTUClass.cs" />
<Compile Include="Communication\ProtocolType.cs" />
<Compile Include="Device\Value\ValueDescriptionFunc.cs" />
<Compile Include="Communication\ValueEncoders\ArrayManipulator.cs" />
<Compile Include="Communication\ValueEncoders\DeviceValueEncoder.cs" />
<Compile Include="Communication\ValueEncoders\LayoutType.cs" />
<Compile Include="Communication\ValueEncoders\StringEncoder.cs" />
<Compile Include="Communication\ValueEncoders\StringEncoderEmail.cs" />
<Compile Include="Communication\ValueEncoders\StringEncoderEmail_Q_Types.cs" />
<Compile Include="Communication\ValueEncoders\StringEncoderUnicode.cs" />
<Compile Include="Communication\ValueEncoders\StringEncoder_W1252.cs" />
<Compile Include="Communication\ValueEncoders\U32_IP_Encoder.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>