mudbus_master_csharp project added directly to the solution
This commit is contained in:
parent
f83e576be3
commit
2adc8756bc
@ -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}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -1 +1 @@
|
||||
bf6bb8fceb3db5a9977dadc407cf576684bf7127
|
||||
89102b0142e574de38a9f47d370f3334e5e6c268
|
||||
|
||||
@ -1 +1 @@
|
||||
247396738e2c5d26ac00f9df05c0cc5c61d7f33a
|
||||
338bdd8d71c148c9df0972f903098eb23eacf0c9
|
||||
|
||||
@ -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>
|
||||
|
||||
6
Common/modbus_master_csharp/App.config
Normal file
6
Common/modbus_master_csharp/App.config
Normal 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>
|
||||
111
Common/modbus_master_csharp/Base/AppConst.cs
Normal file
111
Common/modbus_master_csharp/Base/AppConst.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
314
Common/modbus_master_csharp/Base/ByteArrayExtensionClass.cs
Normal file
314
Common/modbus_master_csharp/Base/ByteArrayExtensionClass.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
153
Common/modbus_master_csharp/Base/Convert1970SecToTime.cs
Normal file
153
Common/modbus_master_csharp/Base/Convert1970SecToTime.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
|
||||
459
Common/modbus_master_csharp/Base/DataUnion.cs
Normal file
459
Common/modbus_master_csharp/Base/DataUnion.cs
Normal 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
|
||||
|
||||
};
|
||||
}
|
||||
115
Common/modbus_master_csharp/Base/Files/PathTools.cs
Normal file
115
Common/modbus_master_csharp/Base/Files/PathTools.cs
Normal 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("\\"));
|
||||
}
|
||||
}
|
||||
}
|
||||
212
Common/modbus_master_csharp/Base/Files/ProgramLogCSVFileClass.cs
Normal file
212
Common/modbus_master_csharp/Base/Files/ProgramLogCSVFileClass.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Common/modbus_master_csharp/Base/LogMessageTool.cs
Normal file
102
Common/modbus_master_csharp/Base/LogMessageTool.cs
Normal 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
602
Common/modbus_master_csharp/Base/NumberConvert.cs
Normal file
602
Common/modbus_master_csharp/Base/NumberConvert.cs
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
474
Common/modbus_master_csharp/Base/StringConvert.cs
Normal file
474
Common/modbus_master_csharp/Base/StringConvert.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Common/modbus_master_csharp/Base/XML/XMLStringClass.cs
Normal file
127
Common/modbus_master_csharp/Base/XML/XMLStringClass.cs
Normal 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("&", "&").
|
||||
Replace("<", "<").
|
||||
Replace(">", ">").
|
||||
Replace("\"", """).
|
||||
Replace("'", "'").
|
||||
Replace("\r", "
").
|
||||
Replace("\n", "
");
|
||||
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("&", "&").
|
||||
Replace("<", "<").
|
||||
Replace(">", ">").
|
||||
Replace(""", "\"").
|
||||
Replace("'", "'").
|
||||
Replace("
", "\r").
|
||||
Replace("
", "\n");
|
||||
return txtToReinset;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("Error in XMLFileIOClass and StripIllegalXMLChars() " + (txtToReinset != null ? " txtToClean = " + txtToReinset.ToString() : "txtToClean is null"), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Common/modbus_master_csharp/Base/XML/XMLWriteFuncClass.cs
Normal file
66
Common/modbus_master_csharp/Base/XML/XMLWriteFuncClass.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Common/modbus_master_csharp/Communication/FuncTypes.cs
Normal file
22
Common/modbus_master_csharp/Communication/FuncTypes.cs
Normal 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,
|
||||
};
|
||||
}
|
||||
634
Common/modbus_master_csharp/Communication/ModbusCom.cs
Normal file
634
Common/modbus_master_csharp/Communication/ModbusCom.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
11
Common/modbus_master_csharp/Communication/ProtocolType.cs
Normal file
11
Common/modbus_master_csharp/Communication/ProtocolType.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace XYLEM.Communication
|
||||
{
|
||||
//------------------------------------- Define ------------------------------------------------
|
||||
public enum ProtocolType : int
|
||||
{
|
||||
ModbusRTU = 0,
|
||||
None,
|
||||
};
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
@ -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 ); }
|
||||
}
|
||||
}
|
||||
@ -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 ); }
|
||||
}
|
||||
}
|
||||
@ -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 ); }
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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" ) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
120
Common/modbus_master_csharp/Device/CalibrationPoint.cs
Normal file
120
Common/modbus_master_csharp/Device/CalibrationPoint.cs
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
198
Common/modbus_master_csharp/Device/CalibrationPoints.cs
Normal file
198
Common/modbus_master_csharp/Device/CalibrationPoints.cs
Normal 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
|
||||
}
|
||||
}
|
||||
156
Common/modbus_master_csharp/Device/IMagFluxRequestProtocol.cs
Normal file
156
Common/modbus_master_csharp/Device/IMagFluxRequestProtocol.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
1125
Common/modbus_master_csharp/Device/MagFlux6200.cs
Normal file
1125
Common/modbus_master_csharp/Device/MagFlux6200.cs
Normal file
File diff suppressed because it is too large
Load Diff
1105
Common/modbus_master_csharp/Device/MagFlux6200_metrology_reg_list.cs
Normal file
1105
Common/modbus_master_csharp/Device/MagFlux6200_metrology_reg_list.cs
Normal file
File diff suppressed because it is too large
Load Diff
319
Common/modbus_master_csharp/Device/ModbusDeviceCom.cs
Normal file
319
Common/modbus_master_csharp/Device/ModbusDeviceCom.cs
Normal 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 ---------------------
|
||||
}
|
||||
}
|
||||
93
Common/modbus_master_csharp/Device/Value/ValueDataType.cs
Normal file
93
Common/modbus_master_csharp/Device/Value/ValueDataType.cs
Normal 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
|
||||
}
|
||||
}
|
||||
146
Common/modbus_master_csharp/Device/Value/ValueDescriptionFunc.cs
Normal file
146
Common/modbus_master_csharp/Device/Value/ValueDescriptionFunc.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Common/modbus_master_csharp/Device/md_test.cs
Normal file
155
Common/modbus_master_csharp/Device/md_test.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
785
Common/modbus_master_csharp/Program.cs
Normal file
785
Common/modbus_master_csharp/Program.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Common/modbus_master_csharp/Properties/AssemblyInfo.cs
Normal file
36
Common/modbus_master_csharp/Properties/AssemblyInfo.cs
Normal 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")]
|
||||
89
Common/modbus_master_csharp/modbus_master_csharp.csproj
Normal file
89
Common/modbus_master_csharp/modbus_master_csharp.csproj
Normal 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>
|
||||
Loading…
Reference in New Issue
Block a user