Files
KinginfoGateway/framework/Foundation/ThingsGateway.Foundation.Adapter.Modbus/Modbus/ModbusHelper.cs
2023-10-16 20:36:51 +08:00

335 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Text;
using ThingsGateway.Foundation.Extension.Bool;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation.Adapter.Modbus;
internal class ModbusHelper
{
/// <summary>
/// 添加Crc16
/// </summary>
internal static byte[] AddCrc(byte[] command)
{
return EasyCRC16.CRC16(command);
}
/// <summary>
/// 添加ModbusTcp报文头
/// </summary>
internal static byte[] AddModbusTcpHead(byte[] modbus, ushort id)
{
byte[] tcp = new byte[modbus.Length + 6];
tcp[0] = BitConverter.GetBytes(id)[1];
tcp[1] = BitConverter.GetBytes(id)[0];
tcp[4] = BitConverter.GetBytes(modbus.Length)[1];
tcp[5] = BitConverter.GetBytes(modbus.Length)[0];
modbus.CopyTo(tcp, 6);
return tcp;
}
/// <summary>
/// modbus地址格式说明
/// </summary>
/// <returns></returns>
internal static string GetAddressDescription()
{
StringBuilder stringBuilder = new();
stringBuilder.AppendLine("Modbus寄存器");
stringBuilder.AppendLine("线圈寄存器使用从 00001 开始的地址编号。");
stringBuilder.AppendLine("离散输入寄存器使用从 10001 开始的地址编号。");
stringBuilder.AppendLine("输入寄存器使用从 30001 开始的地址编号。");
stringBuilder.AppendLine("保持寄存器使用从 40001 开始的地址编号。");
stringBuilder.AppendLine("举例:");
stringBuilder.AppendLine("40001=>保持寄存器第一个寄存器");
stringBuilder.AppendLine("额外格式:");
stringBuilder.AppendLine("设备站号 比如40001;s=2; 代表设备地址为2的保持寄存器第一个寄存器");
stringBuilder.AppendLine("写入功能码 比如40001;w=16; 代表保持寄存器第一个寄存器写入值时采用0x10功能码而不是默认的0x06功能码");
return stringBuilder.ToString();
}
/// <summary>
/// 通过错误码来获取到对应的文本消息
/// </summary>
internal static string GetDescriptionByErrorCode(byte code)
{
return code switch
{
1 => "不支持的功能码",
2 => "读取寄存器越界",
3 => "读取长度超限",
4 => "读写异常",
_ => "未知错误",
};
}
/// <summary>
/// 获取modbus数据区内容返回数据需去除Crc和报文头例如01 03 02 00 01发送数据需报文头
/// </summary>
/// <param name="send">发送数据</param>
/// <param name="response">返回数据</param>
/// <returns></returns>
internal static OperResult<byte[], FilterResult> GetModbusData(byte[] send, byte[] response)
{
try
{
if (response.Length < 3)
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
if (response[1] >= 0x80)//错误码
return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success };
if (response[1] <= 0x05)
{
if ((response.Length < response[2] + 3))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
else
{
if ((response.Length < 6))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
if (send.Length == 0)
{
var result = OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3), FilterResult.Success);
result.Message = "接收数据正确,但主机并没有主动请求数据";
return result;
}
if (send[0] != response[0])
return new OperResult<byte[], FilterResult>(string.Format("站号不一致", send[0], response[0])) { Content2 = FilterResult.Success };
if (send[1] != response[1])
return new OperResult<byte[], FilterResult>() { Message = "功能码不一致", Content2 = FilterResult.Success };
return OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3), FilterResult.Success);
}
catch (Exception ex)
{
return new OperResult<byte[], FilterResult>(ex) { Content2 = FilterResult.Success };
}
}
/// <summary>
/// 去除Crc返回modbus数据区
/// </summary>
/// <param name="send"></param>
/// <param name="response"></param>
/// <param name="crcCheck"></param>
/// <returns></returns>
internal static OperResult<byte[], FilterResult> GetModbusRtuData(byte[] send, byte[] response, bool crcCheck = true)
{
if (response.Length < 3)
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
if (response[1] >= 0x80)//错误码
return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success };
if (response[1] <= 0x05)
{
if ((response.Length < response[2] + 5))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
else
{
if ((response.Length < 8))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
var data = response.SelectMiddle(0, response[2] != 0 ? response[2] + 5 : 8);
if (crcCheck && !EasyCRC16.CheckCRC16(data))
return new OperResult<byte[], FilterResult>("Crc校验失败" + DataTransUtil.ByteToHexString(data, ' ')) { Content2 = FilterResult.Success };
return GetModbusData(send, data.RemoveLast(2));
}
/// <summary>
/// 获取读取报文
/// </summary>
internal static OperResult<byte[]> GetReadModbusCommand(string address, int length, byte station)
{
try
{
var mAddress = ModbusAddress.ParseFrom(address, station);
return OperResult.CreateSuccessResult(GetReadModbusCommand(mAddress, length));
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取写入布尔量报文,根据地址识别功能码
/// </summary>
internal static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool[] values, byte station)
{
try
{
var mAddress = ModbusAddress.ParseFrom(address, station);
//功能码或实际长度
if (values?.Length > 1 || mAddress.WriteFunction == 15)
return GetWriteBoolModbusCommand(mAddress, values, values.Length);
else
return GetWriteBoolModbusCommand(address, values[0], station);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取写入字报文,根据地址识别功能码
/// </summary>
internal static OperResult<byte[]> GetWriteModbusCommand(string address, byte[] value, byte station)
{
try
{
var mAddress = ModbusAddress.ParseFrom(address, station);
//功能码或实际长度
if (value?.Length > 2 || mAddress.WriteFunction == 16)
return OperResult.CreateSuccessResult(GetWriteModbusCommand(mAddress, value));
else
return OperResult.CreateSuccessResult(GetWriteOneModbusCommand(mAddress, value));
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取读取报文
/// </summary>
internal static byte[] GetReadModbusCommand(ModbusAddress mAddress, int length)
{
byte[] array = new byte[6]
{
(byte) mAddress.Station,
(byte) mAddress.ReadFunction,
BitConverter.GetBytes(mAddress.AddressStart)[1],
BitConverter.GetBytes(mAddress.AddressStart)[0],
BitConverter.GetBytes(length)[1],
BitConverter.GetBytes(length)[0]
};
return array;
}
/// <summary>
/// 获取05写入布尔量报文
/// </summary>
internal static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool value, byte station)
{
try
{
if (address.IndexOf('.') <= 0)
{
var mAddress = ModbusAddress.ParseFrom(address, station);
return OperResult.CreateSuccessResult(GetWriteBoolModbusCommand(mAddress, value));
}
return new("不支持写入字寄存器的某一位");
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取05写入布尔量报文
/// </summary>
private static byte[] GetWriteBoolModbusCommand(ModbusAddress mAddress, bool value)
{
byte[] array = new byte[6]
{
(byte) mAddress.Station,
(byte)5,
BitConverter.GetBytes(mAddress.AddressStart)[1],
BitConverter.GetBytes(mAddress.AddressStart)[0],
0,
0
};
if (value)
{
array[4] = 0xFF;
array[5] = 0;
}
else
{
array[4] = 0;
array[5] = 0;
}
return array;
}
/// <summary>
/// 获取15写入布尔量报文
/// </summary>
internal static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool[] values, int length)
{
try
{
byte[] numArray1 = values.BoolArrayToByte();
byte[] numArray2 = new byte[7 + numArray1.Length];
numArray2[0] = (byte)mAddress.Station;
numArray2[1] = (byte)15;
numArray2[2] = BitConverter.GetBytes(mAddress.AddressStart)[1];
numArray2[3] = BitConverter.GetBytes(mAddress.AddressStart)[0];
numArray2[4] = (byte)(length / 256);
numArray2[5] = (byte)(length % 256);
numArray2[6] = (byte)numArray1.Length;
numArray1.CopyTo(numArray2, 7);
return OperResult.CreateSuccessResult(numArray2);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取16写入字报文
/// </summary>
internal static byte[] GetWriteModbusCommand(ModbusAddress mAddress, byte[] values)
{
byte[] numArray = new byte[7 + values.Length];
numArray[0] = (byte)mAddress.Station;
numArray[1] = (byte)16;
numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1];
numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0];
numArray[4] = (byte)(values.Length / 2 / 256);
numArray[5] = (byte)(values.Length / 2 % 256);
numArray[6] = (byte)values.Length;
values.CopyTo(numArray, 7);
return numArray;
}
/// <summary>
/// 获取6写入字报文
/// </summary>
internal static byte[] GetWriteOneModbusCommand(ModbusAddress mAddress, byte[] values)
{
byte[] numArray = new byte[4 + values.Length];
numArray[0] = (byte)mAddress.Station;
numArray[1] = (byte)6;
numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1];
numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0];
values.CopyTo(numArray, 4);
return numArray;
}
}