You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
7.7 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HslCommunication.Core.Address;
namespace HslCommunication.ModBus
{
/// <summary>
/// Modbus协议相关的一些信息
/// </summary>
public class ModbusInfo
{
#region Function Declaration
/// <summary>
/// 读取线圈
/// </summary>
public const byte ReadCoil = 0x01;
/// <summary>
/// 读取离散量
/// </summary>
public const byte ReadDiscrete = 0x02;
/// <summary>
/// 读取寄存器
/// </summary>
public const byte ReadRegister = 0x03;
/// <summary>
/// 读取输入寄存器
/// </summary>
public const byte ReadInputRegister = 0x04;
/// <summary>
/// 写单个线圈
/// </summary>
public const byte WriteOneCoil = 0x05;
/// <summary>
/// 写单个寄存器
/// </summary>
public const byte WriteOneRegister = 0x06;
/// <summary>
/// 写多个线圈
/// </summary>
public const byte WriteCoil = 0x0F;
/// <summary>
/// 写多个寄存器
/// </summary>
public const byte WriteRegister = 0x10;
#endregion
#region ErrCode Declaration
/// <summary>
/// 不支持该功能码
/// </summary>
public const byte FunctionCodeNotSupport = 0x01;
/// <summary>
/// 该地址越界
/// </summary>
public const byte FunctionCodeOverBound = 0x02;
/// <summary>
/// 读取长度超过最大值
/// </summary>
public const byte FunctionCodeQuantityOver = 0x03;
/// <summary>
/// 读写异常
/// </summary>
public const byte FunctionCodeReadWriteException = 0x04;
#endregion
#region Static Helper Method
/// <summary>
/// 将modbus指令打包成Modbus-Tcp指令
/// </summary>
/// <param name="value">Modbus指令</param>
/// <param name="id">消息的序号</param>
/// <returns>Modbus-Tcp指令</returns>
public static byte[] PackCommandToTcp( byte[] value, ushort id )
{
byte[] buffer = new byte[value.Length + 6];
buffer[0] = BitConverter.GetBytes( id )[1];
buffer[1] = BitConverter.GetBytes( id )[0];
buffer[4] = BitConverter.GetBytes( value.Length )[1];
buffer[5] = BitConverter.GetBytes( value.Length )[0];
value.CopyTo( buffer, 6 );
return buffer;
}
#if !NETSTANDARD2_0
/// <summary>
/// 将modbus指令打包成Modbus-Rtu指令
/// </summary>
/// <param name="value">Modbus指令</param>
/// <returns>Modbus-Rtu指令</returns>
public static byte[] PackCommandToRtu( byte[] value )
{
return Serial.SoftCRC16.CRC16( value );
}
/// <summary>
/// 将一个modbus-rtu的数据报文转换成modbus-ascii的数据报文
/// </summary>
/// <param name="value">modbus-rtu的完整报文携带相关的校验码</param>
/// <returns>可以用于直接发送的modbus-ascii的报文</returns>
public static byte[] TransRtuToAsciiPackCommand( byte[] value )
{
// remove crc check
byte[] modbus = BasicFramework.SoftBasic.BytesArrayRemoveLast( value, 2 );
// add LRC check
byte[] modbus_lrc = Serial.SoftLRC.LRC( modbus );
// Translate to ascii information
byte[] modbus_ascii = BasicFramework.SoftBasic.BytesToAsciiBytes( modbus_lrc );
// add head and end informarion
return BasicFramework.SoftBasic.SpliceTwoByteArray( BasicFramework.SoftBasic.SpliceTwoByteArray( new byte[] { 0x3A }, modbus_ascii ), new byte[] { 0x0D, 0x0A } );
}
/// <summary>
/// 将一个modbus-ascii的数据报文转换成的modbus核心数据报文
/// </summary>
/// <param name="value">modbus-ascii的完整报文携带相关的校验码</param>
/// <returns>可以用于直接发送的modbus的报文</returns>
public static OperateResult<byte[]> TransAsciiPackCommandToRtu( byte[] value )
{
try
{
// response check
if (value[0] != 0x3A || value[value.Length - 2] != 0x0D || value[value.Length - 1] != 0x0A)
return new OperateResult<byte[]>( ) { Message = StringResources.Language.ModbusAsciiFormatCheckFailed + BasicFramework.SoftBasic.ByteToHexString( value ) };
// remove head and end
byte[] modbus_ascii = BasicFramework.SoftBasic.BytesArrayRemoveDouble( value, 1, 2 );
// get modbus core
byte[] modbus_core = BasicFramework.SoftBasic.AsciiBytesToBytes( modbus_ascii );
if (!Serial.SoftLRC.CheckLRC( modbus_core ))
return new OperateResult<byte[]>( ) { Message = StringResources.Language.ModbusLRCCheckFailed + BasicFramework.SoftBasic.ByteToHexString( modbus_core ) };
// remove the last info
return OperateResult.CreateSuccessResult( BasicFramework.SoftBasic.BytesArrayRemoveLast( modbus_core, 1 ) );
}
catch(Exception ex)
{
return new OperateResult<byte[]>( ) { Message = ex.Message + BasicFramework.SoftBasic.ByteToHexString( value ) };
}
}
#endif
/// <summary>
/// 分析Modbus协议的地址信息该地址适应于tcp及rtu模式
/// </summary>
/// <param name="address">带格式的地址,比如"100""x=4;100""s=1;100","s=1;x=4;100"</param>
/// <param name="isStartWithZero">起始地址是否从0开始</param>
/// <param name="defaultFunction">默认的功能码信息</param>
/// <returns>转换后的地址信息</returns>
public static OperateResult<ModbusAddress> AnalysisAddress( string address, bool isStartWithZero, byte defaultFunction )
{
try
{
ModbusAddress mAddress = new ModbusAddress( address, defaultFunction );
if (!isStartWithZero)
{
if (mAddress.Address < 1) throw new Exception( StringResources.Language.ModbusAddressMustMoreThanOne );
mAddress.Address = (ushort)(mAddress.Address - 1);
}
return OperateResult.CreateSuccessResult( mAddress );
}
catch (Exception ex)
{
return new OperateResult<ModbusAddress>( ) { Message = ex.Message };
}
}
/// <summary>
/// 通过错误码来获取到对应的文本消息
/// </summary>
/// <param name="code">错误码</param>
/// <returns>错误的文本描述</returns>
public static string GetDescriptionByErrorCode( byte code )
{
switch (code)
{
case ModbusInfo.FunctionCodeNotSupport: return StringResources.Language.ModbusTcpFunctionCodeNotSupport;
case ModbusInfo.FunctionCodeOverBound: return StringResources.Language.ModbusTcpFunctionCodeOverBound;
case ModbusInfo.FunctionCodeQuantityOver: return StringResources.Language.ModbusTcpFunctionCodeQuantityOver;
case ModbusInfo.FunctionCodeReadWriteException: return StringResources.Language.ModbusTcpFunctionCodeReadWriteException;
default: return StringResources.Language.UnknownError;
}
}
#endregion
}
}