From 61b6c6c5e206136ff1a493c093f0520d52360382 Mon Sep 17 00:00:00 2001 From: luosheng Date: Sun, 16 Jul 2023 20:57:48 +0800 Subject: [PATCH] HJ212 Implementation --- Modbus.Net/Modbus.Net.HJ212/HJ212Machine.cs | 97 +++++++++++++ Modbus.Net/Modbus.Net.HJ212/HJ212Protocol.cs | 130 ++++++++++++++++++ .../Modbus.Net.HJ212/HJ212ProtocolLinker.cs | 24 ++++ .../HJ212ProtocolLinkerBytesExtend.cs | 42 ++++++ Modbus.Net/Modbus.Net.HJ212/HJ212Utility.cs | 61 ++++++++ .../Modbus.Net.HJ212/Modbus.Net.HJ212.csproj | 39 ++++++ Modbus.Net/Modbus.Net.HJ212/README.md | 7 + Modbus.Net/Modbus.Net.sln | 10 ++ 8 files changed, 410 insertions(+) create mode 100644 Modbus.Net/Modbus.Net.HJ212/HJ212Machine.cs create mode 100644 Modbus.Net/Modbus.Net.HJ212/HJ212Protocol.cs create mode 100644 Modbus.Net/Modbus.Net.HJ212/HJ212ProtocolLinker.cs create mode 100644 Modbus.Net/Modbus.Net.HJ212/HJ212ProtocolLinkerBytesExtend.cs create mode 100644 Modbus.Net/Modbus.Net.HJ212/HJ212Utility.cs create mode 100644 Modbus.Net/Modbus.Net.HJ212/Modbus.Net.HJ212.csproj create mode 100644 Modbus.Net/Modbus.Net.HJ212/README.md diff --git a/Modbus.Net/Modbus.Net.HJ212/HJ212Machine.cs b/Modbus.Net/Modbus.Net.HJ212/HJ212Machine.cs new file mode 100644 index 0000000..45600f1 --- /dev/null +++ b/Modbus.Net/Modbus.Net.HJ212/HJ212Machine.cs @@ -0,0 +1,97 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Modbus.Net.HJ212 +{ + public class HJ212Machine : BaseMachine where TKey : IEquatable + where TUnitKey : IEquatable + { + private static readonly ILogger> logger = LogProvider.CreateLogger>(); + + private readonly int _maxErrorCount = 3; + + protected string ST { get; } + + protected string CN { get; } + + protected string PW { get; } + + protected string MN { get; } + + private int ErrorCount { get; set; } + + /// + /// 构造函数 + /// + /// 设备的ID号 + /// 连接地址 + /// 需要读写的地址 + public HJ212Machine(TKey id, string connectionString, string st, string cn, string pw, string mn) + : base(id, null, true) + { + BaseUtility = new HJ212Utility(connectionString); + ST = st; + CN = cn; + PW = pw; + MN = mn; + } + + public override async Task> SetDatasAsync(MachineDataType setDataType, Dictionary values) + { + try + { + //检测并连接设备 + if (!BaseUtility.IsConnected) + await BaseUtility.ConnectAsync(); + //如果设备无法连接,终止 + if (!BaseUtility.IsConnected) return new ReturnStruct() + { + Datas = false, + IsSuccess = false, + ErrorCode = -1, + ErrorMsg = "Connection Error" + }; + + //遍历每个要设置的值 + Dictionary formatValues = new Dictionary(); + foreach (var value in values) + { + //根据设置类型找到对应的地址描述 + formatValues.Add(value.Key, value.Value.ToString()); + } + var sendValues = new List>() { formatValues }; + //写入数据 + await + BaseUtility.GetUtilityMethods().SetDatasAsync("0", new object[] { ST, CN, PW, MN, sendValues, DateTime.Now }); + + //如果不保持连接,断开连接 + if (!KeepConnect) + BaseUtility.Disconnect(); + } + catch (Exception e) + { + ErrorCount++; + logger.LogError(e, $"BaseMachine -> SetDatas, Id:{Id} Connection:{ConnectionToken} error. ErrorCount {ErrorCount}."); + + if (ErrorCount >= _maxErrorCount) + Disconnect(); + return new ReturnStruct() + { + Datas = false, + IsSuccess = false, + ErrorCode = -100, + ErrorMsg = "Unknown Exception" + }; + } + return new ReturnStruct() + { + Datas = true, + IsSuccess = true, + ErrorCode = 0, + ErrorMsg = "" + }; + } + } +} diff --git a/Modbus.Net/Modbus.Net.HJ212/HJ212Protocol.cs b/Modbus.Net/Modbus.Net.HJ212/HJ212Protocol.cs new file mode 100644 index 0000000..4ce6be3 --- /dev/null +++ b/Modbus.Net/Modbus.Net.HJ212/HJ212Protocol.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Modbus.Net.HJ212 +{ + /// + /// HJ212协议 + /// + public class HJ212Protocol : BaseProtocol + { + /// + /// 构造函数 + /// + public HJ212Protocol(string connectionToken) + : base(0, 0, Endian.BigEndianLsb) + { + ProtocolLinker = new HJ212ProtocolLinker(connectionToken); + } + + /// + /// 连接 + /// + /// 是否连接成功 + public override async Task ConnectAsync() + { + return await ProtocolLinker.ConnectAsync(); + } + } + + #region 写数据 + /// + /// 写数据协议 + /// + public class WriteRequestHJ212Protocol : ProtocolUnit + { + /// + /// 从对象的参数数组格式化 + /// + /// 非结构化的输入数据 + /// 格式化后的字节流 + public override byte[] Format(IInputStruct message) + { + var r_message = (WriteRequestHJ212InputStruct)message; + string formatMessage = "##0633"; + formatMessage += "QN=" + r_message.QN + ";"; + formatMessage += "ST=" + r_message.ST + ";"; + formatMessage += "CN=" + r_message.CN + ";"; + formatMessage += "PW=" + r_message.PW + ";"; + formatMessage += "MN=" + r_message.MN + ";"; + formatMessage += "CP=&&"; + formatMessage += "DateTime=" + r_message.Datetime.ToString("yyyyMMddHHmmss") + ";"; + foreach (var record in r_message.CP) + { + foreach (var data in record) + { + formatMessage += data.Key + "=" + data.Value + ","; + } + formatMessage = formatMessage[..^1]; + formatMessage += ";"; + } + formatMessage = formatMessage[..^1]; + formatMessage += "&&"; + return Encoding.ASCII.GetBytes(formatMessage); + } + + /// + /// 把仪器返回的内容填充到输出结构中 + /// + /// 返回数据的字节流 + /// 转换标记位 + /// 结构化的输出数据 + public override IOutputStruct Unformat(byte[] messageBytes, ref int pos) + { + return new WriteRequestHJ212OutputStruct(Encoding.ASCII.GetString(messageBytes)); + } + } + + /// + /// 写数据输入 + /// + public class WriteRequestHJ212InputStruct : IInputStruct + { + public WriteRequestHJ212InputStruct(string st, string cn, string pw, string mn, List> cp, DateTime datetime) + { + ST = st; + CN = cn; + PW = pw; + MN = mn; + CP = cp; + Datetime = datetime; + } + + public string QN => "20170101000926706"; + + public string ST { get; } + + public string CN { get; } + + public string PW { get; } + + public string MN { get; } + + public List> CP { get; } + + public DateTime Datetime { get; } + } + + /// + /// 写数据输出 + /// + public class WriteRequestHJ212OutputStruct : IOutputStruct + { + /// + /// 构造函数 + /// + /// 读取的数据 + public WriteRequestHJ212OutputStruct(string value) + { + GetValue = value; + } + + /// + /// 读取的地址 + /// + public string GetValue { get; private set; } + } + #endregion +} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.HJ212/HJ212ProtocolLinker.cs b/Modbus.Net/Modbus.Net.HJ212/HJ212ProtocolLinker.cs new file mode 100644 index 0000000..51b0932 --- /dev/null +++ b/Modbus.Net/Modbus.Net.HJ212/HJ212ProtocolLinker.cs @@ -0,0 +1,24 @@ +namespace Modbus.Net.HJ212 +{ + /// + /// HJ212协议连接器 + /// + public class HJ212ProtocolLinker : ProtocolLinker + { + public HJ212ProtocolLinker(string connectionToken) + { + BaseConnector = new TcpConnector(connectionToken, 443); + ((IConnectorWithController)BaseConnector).AddController(new FifoController(1000)); + } + + /// + /// 检查接收的数据是否正确 + /// + /// 接收协议的内容 + /// 协议是否是正确的 + public override bool? CheckRight(byte[] content) + { + return true; + } + } +} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.HJ212/HJ212ProtocolLinkerBytesExtend.cs b/Modbus.Net/Modbus.Net.HJ212/HJ212ProtocolLinkerBytesExtend.cs new file mode 100644 index 0000000..d07317f --- /dev/null +++ b/Modbus.Net/Modbus.Net.HJ212/HJ212ProtocolLinkerBytesExtend.cs @@ -0,0 +1,42 @@ +using System; +using System.Text; + +namespace Modbus.Net.HJ212 +{ + /// + /// Rtu协议字节伸缩 + /// + public class HJ212ProtocolLinkerBytesExtend : IProtocolLinkerBytesExtend + { + /// + /// 协议扩展,协议内容发送前调用 + /// + /// 扩展前的原始协议内容 + /// 扩展后的协议内容 + public byte[] BytesExtend(byte[] content) + { + var crc = new byte[2]; + //Modbus/Rtu协议扩张,增加CRC校验 + var newFormat = new byte[content.Length + 4]; + Crc16.GetInstance().GetCRC(content, ref crc); + Array.Copy(content, 0, newFormat, 0, content.Length); + string crcString = BitConverter.ToString(crc).Replace("-", string.Empty); + var crcCalc = Encoding.ASCII.GetBytes(crcString); + Array.Copy(crcCalc, 0, newFormat, newFormat.Length - 4, 4); + return newFormat; + } + + /// + /// 协议收缩,协议内容接收后调用 + /// + /// 收缩前的完整协议内容 + /// 收缩后的协议内容 + public byte[] BytesDecact(byte[] content) + { + //Modbus/Rtu协议收缩,抛弃后面2个字节的内容 + var newContent = new byte[content.Length - 2]; + Array.Copy(content, 0, newContent, 0, newContent.Length); + return newContent; + } + } +} diff --git a/Modbus.Net/Modbus.Net.HJ212/HJ212Utility.cs b/Modbus.Net/Modbus.Net.HJ212/HJ212Utility.cs new file mode 100644 index 0000000..fd047b1 --- /dev/null +++ b/Modbus.Net/Modbus.Net.HJ212/HJ212Utility.cs @@ -0,0 +1,61 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Modbus.Net.HJ212 +{ + public class HJ212Utility : BaseUtility, PipeUnit> + { + private static readonly ILogger logger = LogProvider.CreateLogger(); + + public HJ212Utility(string connectionString) : base(0, 0) + { + ConnectionString = connectionString; + Wrapper = new HJ212Protocol(connectionString); + } + + public override Endian Endian => throw new NotImplementedException(); + + public override Task> GetDatasAsync(string startAddress, int getByteCount) + { + throw new NotImplementedException(); + } + + public override void SetConnectionType(int connectionType) + { + throw new NotImplementedException(); + } + + public override async Task> SetDatasAsync(string startAddress, object[] setContents) + { + try + { + var writeRequestHJ212InputStruct = + new WriteRequestHJ212InputStruct((string)setContents[0], (string)setContents[1], (string)setContents[2], (string)setContents[3], (List>)setContents[4], (DateTime)setContents[5]); + var writeRequestOpcOutputStruct = + await + Wrapper.SendReceiveAsync(Wrapper[typeof(WriteRequestHJ212Protocol)], + writeRequestHJ212InputStruct); + return new ReturnStruct + { + Datas = writeRequestOpcOutputStruct?.GetValue != null, + IsSuccess = writeRequestOpcOutputStruct?.GetValue != null, + ErrorCode = 0, + ErrorMsg = null, + }; + } + catch (Exception e) + { + logger.LogError(e, $"OpcUtility -> SetDatas: {ConnectionString} error: {e.Message}"); + return new ReturnStruct + { + Datas = false, + IsSuccess = false, + ErrorCode = -100, + ErrorMsg = e.Message + }; + } + } + } +} diff --git a/Modbus.Net/Modbus.Net.HJ212/Modbus.Net.HJ212.csproj b/Modbus.Net/Modbus.Net.HJ212/Modbus.Net.HJ212.csproj new file mode 100644 index 0000000..1b05333 --- /dev/null +++ b/Modbus.Net/Modbus.Net.HJ212/Modbus.Net.HJ212.csproj @@ -0,0 +1,39 @@ + + + + net6.0 + 10.0 + Modbus.Net.HJ212 + Modbus.Net.HJ212 + Modbus.Net.HJ212 + 1.4.2 + Chris L.(Luo Sheng) + Hangzhou Delian Science Technology Co.,Ltd. + Modbus.Net.HJ212 + Modbus.Net Modbus Implementation + Copyright 2023 Hangzhou Delian Science Technology Co.,Ltd. + https://github.com/parallelbgls/Modbus.Net/tree/master/Modbus.Net/Modbus.Net.HJ212 + https://github.com/parallelbgls/Modbus.Net + git + hardware communicate protocol modbus Delian + False + True + True + True + MIT + README.md + snupkg + + + + bin\Debug\Modbus.Net.HJ212.xml + + + + + + + + + + \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.HJ212/README.md b/Modbus.Net/Modbus.Net.HJ212/README.md new file mode 100644 index 0000000..b9b4c3d --- /dev/null +++ b/Modbus.Net/Modbus.Net.HJ212/README.md @@ -0,0 +1,7 @@ +Modbus.Net.HJ212 +=================== +[![NuGet](https://img.shields.io/nuget/v/Modbus.Net.HJ212.svg)](https://www.nuget.org/packages/Modbus.Net.HJ212/) + +HJ212 Implementation of Modbus.Net + +Doc has been moved to wiki. diff --git a/Modbus.Net/Modbus.Net.sln b/Modbus.Net/Modbus.Net.sln index 92c3165..77327bc 100644 --- a/Modbus.Net/Modbus.Net.sln +++ b/Modbus.Net/Modbus.Net.sln @@ -45,6 +45,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Technosoftware.DaAeHdaClien EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Technosoftware.DaAeHdaClient.Com", "..\Technosoftware\DaAeHdaClient.Com\Technosoftware.DaAeHdaClient.Com.csproj", "{ACAF0A16-FC51-4369-BFA8-484FF20707D7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modbus.Net.HJ212", "Modbus.Net.HJ212\Modbus.Net.HJ212.csproj", "{057644EF-1407-4C2B-808A-AEF0F2979EA8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -181,6 +183,14 @@ Global {ACAF0A16-FC51-4369-BFA8-484FF20707D7}.Release|Any CPU.Build.0 = Release|Any CPU {ACAF0A16-FC51-4369-BFA8-484FF20707D7}.Release|x64.ActiveCfg = Release|x64 {ACAF0A16-FC51-4369-BFA8-484FF20707D7}.Release|x64.Build.0 = Release|x64 + {057644EF-1407-4C2B-808A-AEF0F2979EA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {057644EF-1407-4C2B-808A-AEF0F2979EA8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {057644EF-1407-4C2B-808A-AEF0F2979EA8}.Debug|x64.ActiveCfg = Debug|Any CPU + {057644EF-1407-4C2B-808A-AEF0F2979EA8}.Debug|x64.Build.0 = Debug|Any CPU + {057644EF-1407-4C2B-808A-AEF0F2979EA8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {057644EF-1407-4C2B-808A-AEF0F2979EA8}.Release|Any CPU.Build.0 = Release|Any CPU + {057644EF-1407-4C2B-808A-AEF0F2979EA8}.Release|x64.ActiveCfg = Release|Any CPU + {057644EF-1407-4C2B-808A-AEF0F2979EA8}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE