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#

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