using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HslCommunication.BasicFramework;
using HslCommunication.Core;
using HslCommunication.Core.IMessage;
using HslCommunication.Core.Net;
namespace HslCommunication.ModBus
{
///
/// Modbus-Tcp协议的客户端通讯类,方便的和服务器进行数据交互
///
public class ModbusTcpNet : NetworkDoubleBase, IReadWriteNet
{
#region Constructor
///
/// 实例化一个MOdbus-Tcp协议的客户端对象
///
public ModbusTcpNet( )
{
softIncrementCount = new SoftIncrementCount( ushort.MaxValue );
}
///
/// 指定服务器地址,端口号,客户端自己的站号来初始化
///
/// 服务器的Ip地址
/// 服务器的端口号
/// 客户端自身的站号
public ModbusTcpNet( string ipAddress, int port = 502, byte station = 0x01 )
{
softIncrementCount = new SoftIncrementCount( ushort.MaxValue );
IpAddress = ipAddress;
Port = port;
this.station = station;
}
#endregion
#region Private Member
private byte station = ModbusInfo.ReadCoil; // 本客户端的站号
private SoftIncrementCount softIncrementCount; // 自增消息的对象
#endregion
#region Address Analysis
///
/// 解析数据地址,解析出地址类型,起始地址
///
/// 数据地址
/// 解析出地址类型,起始地址,DB块的地址
private OperateResult AnalysisAddress( string address )
{
try
{
return OperateResult.CreateSuccessResult( Convert.ToInt32( address ) );
}
catch (Exception ex)
{
return new OperateResult( )
{
Message = ex.Message
};
}
}
#endregion
#region Build Command
///
/// 读取数据的基础指令,需要指定指令码,地址,长度
///
///
///
///
///
private OperateResult BuildReadCommandBase( byte code, string address, ushort count )
{
OperateResult analysis = AnalysisAddress( address );
if (!analysis.IsSuccess) return OperateResult.CreateFailedResult( analysis );
ushort messageId = (ushort)softIncrementCount.GetCurrentValue( );
byte[] buffer = new byte[12];
buffer[0] = (byte)(messageId / 256);
buffer[1] = (byte)(messageId % 256);
buffer[2] = 0x00;
buffer[3] = 0x00;
buffer[4] = 0x00;
buffer[5] = 0x06;
buffer[6] = station;
buffer[7] = code;
buffer[8] = (byte)(analysis.Content / 256);
buffer[9] = (byte)(analysis.Content % 256);
buffer[10] = (byte)(count / 256);
buffer[11] = (byte)(count % 256);
return OperateResult.CreateSuccessResult( buffer );
}
///
/// 生成一个读取线圈的指令头
///
/// 地址
/// 长度
/// 携带有命令字节
private OperateResult BuildReadCoilCommand( string address, ushort count )
{
return BuildReadCommandBase( ModbusInfo.ReadCoil, address, count );
}
///
/// 生成一个读取离散信息的指令头
///
/// 地址
/// 长度
/// 携带有命令字节
private OperateResult BuildReadDiscreteCommand( string address, ushort count )
{
return BuildReadCommandBase( ModbusInfo.ReadDiscrete, address, count );
}
///
/// 生成一个读取寄存器的指令头
///
///
///
/// 携带有命令字节
private OperateResult BuildReadRegisterCommand( string address, ushort count )
{
return BuildReadCommandBase( ModbusInfo.ReadRegister, address, count );
}
private OperateResult BuildWriteOneCoilCommand( string address, bool value )
{
OperateResult analysis = AnalysisAddress( address );
if (!analysis.IsSuccess) return OperateResult.CreateFailedResult( analysis );
ushort messageId = (ushort)softIncrementCount.GetCurrentValue( );
byte[] buffer = new byte[12];
buffer[0] = (byte)(messageId / 256);
buffer[1] = (byte)(messageId % 256);
buffer[2] = 0x00;
buffer[3] = 0x00;
buffer[4] = 0x00;
buffer[5] = 0x06;
buffer[6] = station;
buffer[7] = ModbusInfo.WriteOneCoil;
buffer[8] = (byte)(analysis.Content / 256);
buffer[9] = (byte)(analysis.Content % 256);
buffer[10] = (byte)(value ? 0xFF : 0x00);
buffer[11] = 0x00;
return OperateResult.CreateSuccessResult( buffer );
}
private OperateResult BuildWriteOneRegisterCommand( string address, byte[] data )
{
OperateResult analysis = AnalysisAddress( address );
if (!analysis.IsSuccess) return OperateResult.CreateFailedResult( analysis );
ushort messageId = (ushort)softIncrementCount.GetCurrentValue( );
byte[] buffer = new byte[12];
buffer[0] = (byte)(messageId / 256);
buffer[1] = (byte)(messageId % 256);
buffer[2] = 0x00;
buffer[3] = 0x00;
buffer[4] = 0x00;
buffer[5] = 0x06;
buffer[6] = station;
buffer[7] = ModbusInfo.WriteOneRegister;
buffer[8] = (byte)(analysis.Content / 256);
buffer[9] = (byte)(analysis.Content % 256);
buffer[10] = data[1];
buffer[11] = data[0];
return OperateResult.CreateSuccessResult( buffer );
}
private OperateResult BuildWriteCoilCommand( string address, bool[] values )
{
byte[] data = SoftBasic.BoolArrayToByte( values );
OperateResult analysis = AnalysisAddress( address );
if (!analysis.IsSuccess) return OperateResult.CreateFailedResult( analysis );
ushort messageId = (ushort)softIncrementCount.GetCurrentValue( );
byte[] buffer = new byte[13 + data.Length];
buffer[0] = (byte)(messageId / 256);
buffer[1] = (byte)(messageId % 256);
buffer[2] = 0x00;
buffer[3] = 0x00;
buffer[4] = (byte)((buffer.Length - 6) / 256);
buffer[5] = (byte)((buffer.Length - 6) % 256);
buffer[6] = station;
buffer[7] = ModbusInfo.WriteCoil;
buffer[8] = (byte)(analysis.Content / 256);
buffer[9] = (byte)(analysis.Content % 256);
buffer[10] = (byte)(values.Length / 256);
buffer[11] = (byte)(values.Length % 256);
buffer[12] = (byte)(data.Length);
data.CopyTo( buffer, 13 );
return OperateResult.CreateSuccessResult( buffer );
}
private OperateResult BuildWriteRegisterCommand( string address, byte[] data )
{
OperateResult analysis = AnalysisAddress( address );
if (!analysis.IsSuccess) return OperateResult.CreateFailedResult( analysis );
ushort messageId = (ushort)softIncrementCount.GetCurrentValue( );
byte[] buffer = new byte[13 + data.Length];
buffer[0] = (byte)(messageId / 256);
buffer[1] = (byte)(messageId % 256);
buffer[2] = 0x00;
buffer[3] = 0x00;
buffer[4] = (byte)((buffer.Length - 6) / 256);
buffer[5] = (byte)((buffer.Length - 6) % 256);
buffer[6] = station;
buffer[7] = ModbusInfo.WriteRegister;
buffer[8] = (byte)(analysis.Content / 256);
buffer[9] = (byte)(analysis.Content % 256);
buffer[10] = (byte)(data.Length / 2 / 256);
buffer[11] = (byte)(data.Length / 2 % 256);
buffer[12] = (byte)(data.Length);
data.CopyTo( buffer, 13 );
return OperateResult.CreateSuccessResult( buffer );
}
#endregion
#region Core Interative
///
/// 通过错误码来获取到对应的文本消息
///
///
///
private string GetDescriptionByErrorCode( byte code )
{
switch (code)
{
case ModbusInfo.FunctionCodeNotSupport: return StringResources.ModbusTcpFunctionCodeNotSupport;
case ModbusInfo.FunctionCodeOverBound: return StringResources.ModbusTcpFunctionCodeOverBound;
case ModbusInfo.FunctionCodeQuantityOver: return StringResources.ModbusTcpFunctionCodeQuantityOver;
case ModbusInfo.FunctionCodeReadWriteException: return StringResources.ModbusTcpFunctionCodeReadWriteException;
default: return StringResources.UnknownError;
}
}
private OperateResult CheckModbusTcpResponse( byte[] send )
{
OperateResult result = ReadFromCoreServer( send );
if (result.IsSuccess)
{
if ((send[7] + 0x80) == result.Content[7])
{
// 发生了错误
result.IsSuccess = false;
result.Message = GetDescriptionByErrorCode( result.Content[8] );
result.ErrorCode = result.Content[8];
}
}
return result;
}
#endregion
#region Customer Support
///
/// 读取自定义的数据类型,只针对寄存器而言,需要规定了写入和解析规则
///
/// 类型名称
/// 起始地址
/// 带是否成功的特定类型的对象
public OperateResult ReadCustomer( string address ) where T : IDataTransfer, new()
{
OperateResult result = new OperateResult( );
T Content = new T( );
OperateResult read = Read( address, Content.ReadCount );
if (read.IsSuccess)
{
Content.ParseSource( read.Content );
result.Content = Content;
result.IsSuccess = true;
}
else
{
result.ErrorCode = read.ErrorCode;
result.Message = read.Message;
}
return result;
}
///
/// 写入自定义的数据类型到寄存器去,只要规定了生成字节的方法即可
///
/// 自定义类型
/// 起始地址
/// 实例对象
/// 是否成功
public OperateResult WriteCustomer( string address, T data ) where T : IDataTransfer, new()
{
return Write( address, data.ToSource( ) );
}
#endregion
#region Read Support
///
/// 读取服务器的数据,需要指定不同的功能码
///
/// 指令
/// 地址
/// 长度
///
private OperateResult ReadModBusBase( byte code, string address, ushort length )
{
OperateResult command = BuildReadCommandBase( code, address, length );
if (!command.IsSuccess) return OperateResult.CreateFailedResult( command );
OperateResult resultBytes = CheckModbusTcpResponse( command.Content );
if (resultBytes.IsSuccess)
{
// 二次数据处理
if (resultBytes.Content?.Length >= 9)
{
byte[] buffer = new byte[resultBytes.Content.Length - 9];
Array.Copy( resultBytes.Content, 9, buffer, 0, buffer.Length );
resultBytes.Content = buffer;
}
}
return resultBytes;
}
///
/// 读取线圈,需要指定起始地址
///
/// 起始地址,格式为"1234"
/// 带有成功标志的bool对象
public OperateResult ReadCoil( string address )
{
var read = ReadModBusBase( ModbusInfo.ReadCoil, address, 1 );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
return GetBoolResultFromBytes( read );
}
///
/// 批量的读取线圈,需要指定起始地址,读取长度
///
/// 起始地址,格式为"1234"
/// 读取长度
/// 带有成功标志的bool数组对象
public OperateResult ReadCoil( string address, ushort length )
{
var read = ReadModBusBase( ModbusInfo.ReadCoil, address, length );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
return OperateResult.CreateSuccessResult( SoftBasic.ByteToBoolArray( read.Content, length ) );
}
///
/// 批量的离散变量,需要指定起始地址,读取长度
///
/// 起始地址,格式为"1234"
/// 读取长度
/// 带有成功标志的bool数组对象
public OperateResult ReadDiscrete( string address, ushort length )
{
var read = ReadModBusBase( ModbusInfo.ReadDiscrete, address, length );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
return OperateResult.CreateSuccessResult( SoftBasic.ByteToBoolArray( read.Content, length ) );
}
///
/// 从Modbus服务器批量读取寄存器的信息,需要指定起始地址,读取长度
///
/// 起始地址,格式为"1234"
/// 读取的数量
/// 带有成功标志的字节信息
public OperateResult Read( string address, ushort length )
{
OperateResult analysis = AnalysisAddress( address );
if (!analysis.IsSuccess) return OperateResult.CreateFailedResult( analysis );
List lists = new List( );
ushort alreadyFinished = 0;
while (alreadyFinished < length)
{
ushort lengthTmp = (ushort)Math.Min( (length - alreadyFinished), 120 );
OperateResult read = ReadModBusBase( ModbusInfo.ReadRegister, (analysis.Content + alreadyFinished).ToString( ), lengthTmp );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
lists.AddRange( read.Content );
alreadyFinished += lengthTmp;
}
return OperateResult.CreateSuccessResult( lists.ToArray( ) );
}
///
/// 读取指定地址的short数据
///
/// 起始地址,格式为"1234"
/// 带有成功标志的short数据
public OperateResult ReadInt16( string address )
{
return GetInt16ResultFromBytes( Read( address, 1 ) );
}
///
/// 读取指定地址的ushort数据
///
/// 起始地址,格式为"1234"
/// 带有成功标志的ushort数据
public OperateResult ReadUInt16( string address )
{
return GetUInt16ResultFromBytes( Read( address, 1 ) );
}
///
/// 读取指定地址的int数据
///
/// 起始地址,格式为"1234"
/// 带有成功标志的int数据
public OperateResult ReadInt32( string address )
{
return GetInt32ResultFromBytes( Read( address, 2 ) );
}
///
/// 读取指定地址的uint数据
///
/// 起始地址,格式为"1234"
/// 带有成功标志的uint数据
public OperateResult ReadUInt32( string address )
{
return GetUInt32ResultFromBytes( Read( address, 2 ) );
}
///
/// 读取指定地址的float数据
///
/// 起始地址,格式为"1234"
/// 带有成功标志的float数据
public OperateResult ReadFloat( string address )
{
return GetSingleResultFromBytes( Read( address, 2 ) );
}
///
/// 读取指定地址的long数据
///
/// 起始地址,格式为"1234"
/// 带有成功标志的long数据
public OperateResult ReadInt64( string address )
{
return GetInt64ResultFromBytes( Read( address, 4 ) );
}
///
/// 读取指定地址的ulong数据
///
/// 起始地址,格式为"1234"
/// 带有成功标志的ulong数据
public OperateResult ReadUInt64( string address )
{
return GetUInt64ResultFromBytes( Read( address, 4 ) );
}
///
/// 读取指定地址的double数据
///
/// 起始地址,格式为"1234"
/// 带有成功标志的double数据
public OperateResult ReadDouble( string address )
{
return GetDoubleResultFromBytes( Read( address, 4 ) );
}
///
/// 读取地址地址的String数据,字符串编码为ASCII
///
/// 起始地址,格式为"1234"
/// 字符串长度
/// 带有成功标志的string数据
public OperateResult ReadString( string address, ushort length )
{
return GetStringResultFromBytes( Read( address, length ) );
}
#endregion
#region Write One Register
///
/// 写一个寄存器数据
///
/// 起始地址
/// 高位
/// 地位
/// 返回写入结果
public OperateResult WriteOneRegister( string address, byte high, byte low )
{
OperateResult command = BuildWriteOneRegisterCommand( address, new byte[] { high, low } );
if (!command.IsSuccess)
{
return command;
}
return CheckModbusTcpResponse( command.Content );
}
///
/// 写一个寄存器数据
///
/// 起始地址
/// 写入值
/// 返回写入结果
public OperateResult WriteOneRegister( string address, short value )
{
byte[] buffer = BitConverter.GetBytes( value );
return WriteOneRegister( address, buffer[1], buffer[0] );
}
///
/// 写一个寄存器数据
///
/// 起始地址
/// 写入值
/// 返回写入结果
public OperateResult WriteOneRegister( string address, ushort value )
{
byte[] buffer = BitConverter.GetBytes( value );
return WriteOneRegister( address, buffer[1], buffer[0] );
}
#endregion
#region Write Base
///
/// 将数据写入到Modbus的寄存器上去,需要指定起始地址和数据内容
///
/// 起始地址,格式为"1234"
/// 写入的数据,长度根据data的长度来指示
/// 返回写入结果
public OperateResult Write( string address, byte[] value )
{
OperateResult command = BuildWriteRegisterCommand( address, value );
if (!command.IsSuccess)
{
return command;
}
return CheckModbusTcpResponse( command.Content );
}
#endregion
#region Write Coil
///
/// 写一个线圈信息,指定是否通断
///
/// 起始地址
/// 写入值
/// 返回写入结果
public OperateResult WriteCoil( string address, bool value )
{
OperateResult command = BuildWriteOneCoilCommand( address, value );
if (!command.IsSuccess)
{
return command;
}
return CheckModbusTcpResponse( command.Content );
}
///
///
///
/// 起始地址
/// 写入值
/// 返回写入结果
public OperateResult WriteCoil( string address, bool[] values )
{
OperateResult command = BuildWriteCoilCommand( address, values );
if (!command.IsSuccess)
{
return command;
}
return CheckModbusTcpResponse( command.Content );
}
#endregion
#region Write String
///
/// 向寄存器中写入字符串,编码格式为ASCII
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, string value )
{
byte[] temp = Encoding.ASCII.GetBytes( value );
return Write( address, temp );
}
///
/// 向寄存器中写入指定长度的字符串,超出截断,不够补0,编码格式为ASCII
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 指定的字符串长度,必须大于0
/// 返回写入结果
public OperateResult Write( string address, string value, int length )
{
byte[] temp = Encoding.ASCII.GetBytes( value );
temp = BasicFramework.SoftBasic.ArrayExpandToLength( temp, length );
return Write( address, temp );
}
///
/// 向寄存器中写入字符串,编码格式为Unicode
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult WriteUnicodeString( string address, string value )
{
byte[] temp = Encoding.Unicode.GetBytes( value );
return Write( address, temp );
}
///
/// 向寄存器中写入指定长度的字符串,超出截断,不够补0,编码格式为Unicode
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 指定的字符串长度,必须大于0
/// 返回写入结果
public OperateResult WriteUnicodeString( string address, string value, int length )
{
byte[] temp = Encoding.Unicode.GetBytes( value );
temp = SoftBasic.ArrayExpandToLength( temp, length * 2 );
return Write( address, temp );
}
#endregion
#region Write bool[]
///
/// 向寄存器中写入bool数组,返回值说明,比如你写入M100,那么data[0]对应M100.0
///
/// 要写入的数据地址
/// 要写入的实际数据,长度为8的倍数
/// 返回写入结果
public OperateResult Write( string address, bool[] values )
{
return Write( address, BasicFramework.SoftBasic.BoolArrayToByte( values ) );
}
#endregion
#region Write Short
///
/// 向寄存器中写入short数组,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, short[] values )
{
return Write( address, ByteTransform.TransByte( values ) );
}
///
/// 向寄存器中写入short数据,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, short value )
{
return Write( address, new short[] { value } );
}
#endregion
#region Write UShort
///
/// 向寄存器中写入ushort数组,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, ushort[] values )
{
return Write( address, ByteTransform.TransByte( values ) );
}
///
/// 向寄存器中写入ushort数据,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, ushort value )
{
return Write( address, new ushort[] { value } );
}
#endregion
#region Write Int
///
/// 向寄存器中写入int数组,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, int[] values )
{
return Write( address, ByteTransform.TransByte( values ) );
}
///
/// 向寄存器中写入int数据,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, int value )
{
return Write( address, new int[] { value } );
}
#endregion
#region Write UInt
///
/// 向寄存器中写入uint数组,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, uint[] values )
{
return Write( address, ByteTransform.TransByte( values ) );
}
///
/// 向寄存器中写入uint数据,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, uint value )
{
return Write( address, new uint[] { value } );
}
#endregion
#region Write Float
///
/// 向寄存器中写入float数组,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, float[] values )
{
return Write( address, ByteTransform.TransByte( values ) );
}
///
/// 向寄存器中写入float数据,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, float value )
{
return Write( address, new float[] { value } );
}
#endregion
#region Write Long
///
/// 向寄存器中写入long数组,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, long[] values )
{
return Write( address, ByteTransform.TransByte( values ) );
}
///
/// 向寄存器中写入long数据,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, long value )
{
return Write( address, new long[] { value } );
}
#endregion
#region Write ULong
///
/// 向寄存器中写入ulong数组,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, ulong[] values )
{
return Write( address, ByteTransform.TransByte( values ) );
}
///
/// 向寄存器中写入ulong数据,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, ulong value )
{
return Write( address, new ulong[] { value } );
}
#endregion
#region Write Double
///
/// 向寄存器中写入double数组,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, double[] values )
{
return Write( address, ByteTransform.TransByte( values ) );
}
///
/// 向寄存器中写入double数据,返回值说明
///
/// 要写入的数据地址
/// 要写入的实际数据
/// 返回写入结果
public OperateResult Write( string address, double value )
{
return Write( address, new double[] { value } );
}
#endregion
#region Object Override
///
/// 获取当前对象的字符串标识形式
///
/// 字符串信息
public override string ToString( )
{
return "ModbusTcpNet";
}
#endregion
}
}