HJ212 Implementation

This commit is contained in:
luosheng
2023-07-16 20:57:48 +08:00
parent 2055c10c59
commit 61b6c6c5e2
8 changed files with 410 additions and 0 deletions

View File

@@ -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<TKey, TUnitKey> : BaseMachine<TKey, TUnitKey, string, string> where TKey : IEquatable<TKey>
where TUnitKey : IEquatable<TUnitKey>
{
private static readonly ILogger<HJ212Machine<TKey, TUnitKey>> logger = LogProvider.CreateLogger<HJ212Machine<TKey, TUnitKey>>();
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; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="id">设备的ID号</param>
/// <param name="connectionString">连接地址</param>
/// <param name="getAddresses">需要读写的地址</param>
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<ReturnStruct<bool>> SetDatasAsync(MachineDataType setDataType, Dictionary<string, double> values)
{
try
{
//检测并连接设备
if (!BaseUtility.IsConnected)
await BaseUtility.ConnectAsync();
//如果设备无法连接,终止
if (!BaseUtility.IsConnected) return new ReturnStruct<bool>()
{
Datas = false,
IsSuccess = false,
ErrorCode = -1,
ErrorMsg = "Connection Error"
};
//遍历每个要设置的值
Dictionary<string, string> formatValues = new Dictionary<string, string>();
foreach (var value in values)
{
//根据设置类型找到对应的地址描述
formatValues.Add(value.Key, value.Value.ToString());
}
var sendValues = new List<Dictionary<string, string>>() { formatValues };
//写入数据
await
BaseUtility.GetUtilityMethods<IUtilityMethodDatas>().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<bool>()
{
Datas = false,
IsSuccess = false,
ErrorCode = -100,
ErrorMsg = "Unknown Exception"
};
}
return new ReturnStruct<bool>()
{
Datas = true,
IsSuccess = true,
ErrorCode = 0,
ErrorMsg = ""
};
}
}
}

View File

@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.HJ212
{
/// <summary>
/// HJ212协议
/// </summary>
public class HJ212Protocol : BaseProtocol
{
/// <summary>
/// 构造函数
/// </summary>
public HJ212Protocol(string connectionToken)
: base(0, 0, Endian.BigEndianLsb)
{
ProtocolLinker = new HJ212ProtocolLinker(connectionToken);
}
/// <summary>
/// 连接
/// </summary>
/// <returns>是否连接成功</returns>
public override async Task<bool> ConnectAsync()
{
return await ProtocolLinker.ConnectAsync();
}
}
#region
/// <summary>
/// 写数据协议
/// </summary>
public class WriteRequestHJ212Protocol : ProtocolUnit<byte[], byte[]>
{
/// <summary>
/// 从对象的参数数组格式化
/// </summary>
/// <param name="message">非结构化的输入数据</param>
/// <returns>格式化后的字节流</returns>
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);
}
/// <summary>
/// 把仪器返回的内容填充到输出结构中
/// </summary>
/// <param name="messageBytes">返回数据的字节流</param>
/// <param name="pos">转换标记位</param>
/// <returns>结构化的输出数据</returns>
public override IOutputStruct Unformat(byte[] messageBytes, ref int pos)
{
return new WriteRequestHJ212OutputStruct(Encoding.ASCII.GetString(messageBytes));
}
}
/// <summary>
/// 写数据输入
/// </summary>
public class WriteRequestHJ212InputStruct : IInputStruct
{
public WriteRequestHJ212InputStruct(string st, string cn, string pw, string mn, List<Dictionary<string, string>> 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<Dictionary<string, string>> CP { get; }
public DateTime Datetime { get; }
}
/// <summary>
/// 写数据输出
/// </summary>
public class WriteRequestHJ212OutputStruct : IOutputStruct
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="value">读取的数据</param>
public WriteRequestHJ212OutputStruct(string value)
{
GetValue = value;
}
/// <summary>
/// 读取的地址
/// </summary>
public string GetValue { get; private set; }
}
#endregion
}

View File

@@ -0,0 +1,24 @@
namespace Modbus.Net.HJ212
{
/// <summary>
/// HJ212协议连接器
/// </summary>
public class HJ212ProtocolLinker : ProtocolLinker
{
public HJ212ProtocolLinker(string connectionToken)
{
BaseConnector = new TcpConnector(connectionToken, 443);
((IConnectorWithController<byte[], byte[]>)BaseConnector).AddController(new FifoController(1000));
}
/// <summary>
/// 检查接收的数据是否正确
/// </summary>
/// <param name="content">接收协议的内容</param>
/// <returns>协议是否是正确的</returns>
public override bool? CheckRight(byte[] content)
{
return true;
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Text;
namespace Modbus.Net.HJ212
{
/// <summary>
/// Rtu协议字节伸缩
/// </summary>
public class HJ212ProtocolLinkerBytesExtend : IProtocolLinkerBytesExtend<byte[], byte[]>
{
/// <summary>
/// 协议扩展,协议内容发送前调用
/// </summary>
/// <param name="content">扩展前的原始协议内容</param>
/// <returns>扩展后的协议内容</returns>
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;
}
/// <summary>
/// 协议收缩,协议内容接收后调用
/// </summary>
/// <param name="content">收缩前的完整协议内容</param>
/// <returns>收缩后的协议内容</returns>
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;
}
}
}

View File

@@ -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<byte[], byte[], ProtocolUnit<byte[], byte[]>, PipeUnit>
{
private static readonly ILogger<HJ212Utility> logger = LogProvider.CreateLogger<HJ212Utility>();
public HJ212Utility(string connectionString) : base(0, 0)
{
ConnectionString = connectionString;
Wrapper = new HJ212Protocol(connectionString);
}
public override Endian Endian => throw new NotImplementedException();
public override Task<ReturnStruct<byte[]>> GetDatasAsync(string startAddress, int getByteCount)
{
throw new NotImplementedException();
}
public override void SetConnectionType(int connectionType)
{
throw new NotImplementedException();
}
public override async Task<ReturnStruct<bool>> SetDatasAsync(string startAddress, object[] setContents)
{
try
{
var writeRequestHJ212InputStruct =
new WriteRequestHJ212InputStruct((string)setContents[0], (string)setContents[1], (string)setContents[2], (string)setContents[3], (List<Dictionary<string, string>>)setContents[4], (DateTime)setContents[5]);
var writeRequestOpcOutputStruct =
await
Wrapper.SendReceiveAsync<WriteRequestHJ212OutputStruct>(Wrapper[typeof(WriteRequestHJ212Protocol)],
writeRequestHJ212InputStruct);
return new ReturnStruct<bool>
{
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<bool>
{
Datas = false,
IsSuccess = false,
ErrorCode = -100,
ErrorMsg = e.Message
};
}
}
}
}

View File

@@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks>
<LangVersion>10.0</LangVersion>
<AssemblyName>Modbus.Net.HJ212</AssemblyName>
<RootNamespace>Modbus.Net.HJ212</RootNamespace>
<PackageId>Modbus.Net.HJ212</PackageId>
<Version>1.4.2</Version>
<Authors>Chris L.(Luo Sheng)</Authors>
<Company>Hangzhou Delian Science Technology Co.,Ltd.</Company>
<Product>Modbus.Net.HJ212</Product>
<Description>Modbus.Net Modbus Implementation</Description>
<Copyright>Copyright 2023 Hangzhou Delian Science Technology Co.,Ltd.</Copyright>
<PackageProjectUrl>https://github.com/parallelbgls/Modbus.Net/tree/master/Modbus.Net/Modbus.Net.HJ212</PackageProjectUrl>
<RepositoryUrl>https://github.com/parallelbgls/Modbus.Net</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>hardware communicate protocol modbus Delian</PackageTags>
<PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<IncludeSymbols>True</IncludeSymbols>
<IncludeSource>True</IncludeSource>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>bin\Debug\Modbus.Net.HJ212.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Modbus.Net\Modbus.Net.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath=""/>
</ItemGroup>
</Project>

View File

@@ -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.

View File

@@ -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