ModbusInfo.cs 7.53 KB
using HslCommunication.Core.Address;
using System;

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