using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HslCommunication.Core.Address;
namespace HslCommunication.ModBus
{
///
/// Modbus协议相关的一些信息
///
public class ModbusInfo
{
#region Function Declaration
///
/// 读取线圈
///
public const byte ReadCoil = 0x01;
///
/// 读取离散量
///
public const byte ReadDiscrete = 0x02;
///
/// 读取寄存器
///
public const byte ReadRegister = 0x03;
///
/// 读取输入寄存器
///
public const byte ReadInputRegister = 0x04;
///
/// 写单个线圈
///
public const byte WriteOneCoil = 0x05;
///
/// 写单个寄存器
///
public const byte WriteOneRegister = 0x06;
///
/// 写多个线圈
///
public const byte WriteCoil = 0x0F;
///
/// 写多个寄存器
///
public const byte WriteRegister = 0x10;
#endregion
#region ErrCode Declaration
///
/// 不支持该功能码
///
public const byte FunctionCodeNotSupport = 0x01;
///
/// 该地址越界
///
public const byte FunctionCodeOverBound = 0x02;
///
/// 读取长度超过最大值
///
public const byte FunctionCodeQuantityOver = 0x03;
///
/// 读写异常
///
public const byte FunctionCodeReadWriteException = 0x04;
#endregion
#region Static Helper Method
///
/// 将modbus指令打包成Modbus-Tcp指令
///
/// Modbus指令
/// 消息的序号
/// Modbus-Tcp指令
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
///
/// 将modbus指令打包成Modbus-Rtu指令
///
/// Modbus指令
/// Modbus-Rtu指令
public static byte[] PackCommandToRtu( byte[] value )
{
return Serial.SoftCRC16.CRC16( value );
}
///
/// 将一个modbus-rtu的数据报文,转换成modbus-ascii的数据报文
///
/// modbus-rtu的完整报文,携带相关的校验码
/// 可以用于直接发送的modbus-ascii的报文
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 } );
}
///
/// 将一个modbus-ascii的数据报文,转换成的modbus核心数据报文
///
/// modbus-ascii的完整报文,携带相关的校验码
/// 可以用于直接发送的modbus的报文
public static OperateResult TransAsciiPackCommandToRtu( byte[] value )
{
try
{
// response check
if (value[0] != 0x3A || value[value.Length - 2] != 0x0D || value[value.Length - 1] != 0x0A)
return new OperateResult( ) { 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( ) { 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( ) { Message = ex.Message + BasicFramework.SoftBasic.ByteToHexString( value ) };
}
}
#endif
///
/// 分析Modbus协议的地址信息,该地址适应于tcp及rtu模式
///
/// 带格式的地址,比如"100","x=4;100","s=1;100","s=1;x=4;100"
/// 起始地址是否从0开始
/// 默认的功能码信息
/// 转换后的地址信息
public static OperateResult 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( ) { Message = ex.Message };
}
}
///
/// 通过错误码来获取到对应的文本消息
///
/// 错误码
/// 错误的文本描述
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
}
}