You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
839 lines
34 KiB
839 lines
34 KiB
8 months ago
|
using System;
|
||
|
using System.Linq;
|
||
|
|
||
|
namespace EGFramework{
|
||
|
/// <summary>
|
||
|
/// some extensions function about Modbus-TCP and Modbus-RTU (Physic layer used RS-485)
|
||
|
/// not include Modbus-ASCII,because LRC verify not developed
|
||
|
/// </summary>
|
||
|
public static class EGModbusExtension
|
||
|
{
|
||
|
|
||
|
//Send Protocol
|
||
|
//---------Modbus-TCP's Prefix---------
|
||
|
//[00 00 00 00 00 06] 01 03 00 00 00 08
|
||
|
//00 00 ----- info head (check for reply Any things can be defined)
|
||
|
//xx xx 00 00 00 06 info length ( Max length 65535 )
|
||
|
public static byte[] MakeModbusTCPPrefix(this object self,ushort messageId,uint length){
|
||
|
return messageId.ToBytes().Concat(length.ToBytes()).ToArray();
|
||
|
}
|
||
|
public static byte[] MakeModbusTCPPrefix(this object self,ushort messageId,byte[] sendData){
|
||
|
return messageId.ToBytes().Concat(((uint)sendData.Length).ToBytes()).ToArray();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Modbus FunctionCode
|
||
|
/// 0x01 => Read Coils ---- OK
|
||
|
/// 0x02 => Read Discrete input ---- OK
|
||
|
/// 0x03 => Read Holding registers ---- OK
|
||
|
/// 0x04 => Read Input registers ---- OK
|
||
|
/// 0x05 => Write Single Coils ---- OK
|
||
|
/// 0x06 => Write Single Holding registers ---- OK
|
||
|
/// 0x0F => Write Multi Coils ---- OK
|
||
|
/// 0x10 => Write Multi Holding registers ---- OK
|
||
|
/// </summary>
|
||
|
|
||
|
#region Modbus TCP Request and Response
|
||
|
public struct ModbusTCP_ReadCoils : IRequest
|
||
|
{
|
||
|
public const byte FunctionCode = 0x01;
|
||
|
public const ushort MessageId = 0xFF01;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort ReadCount { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress"></param>
|
||
|
/// <param name="registerAddress"></param>
|
||
|
/// <param name="readCount">Read count should be less than 2000</param>
|
||
|
public ModbusTCP_ReadCoils(byte deviceAddress,ushort registerAddress,ushort readCount){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
ReadCount = readCount;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = this.MakeModbusTCPPrefix(MessageId,6);
|
||
|
protocolRequest = protocolRequest.Append(DeviceAddress).ToArray();
|
||
|
protocolRequest = protocolRequest.Append(FunctionCode).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
if(ReadCount>2000){
|
||
|
ReadCount = 2000;
|
||
|
}
|
||
|
byte[] registerValues = ReadCount.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusTCP_ReadDiscreteInput : IRequest
|
||
|
{
|
||
|
public const byte FunctionCode = 0x02;
|
||
|
public const ushort MessageId = 0xFF02;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort ReadCount { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress"></param>
|
||
|
/// <param name="registerAddress"></param>
|
||
|
/// <param name="readCount">Read count should be less than 2000</param>
|
||
|
public ModbusTCP_ReadDiscreteInput(byte deviceAddress,ushort registerAddress,ushort readCount){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
ReadCount = readCount;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = this.MakeModbusTCPPrefix(MessageId,6);
|
||
|
protocolRequest = protocolRequest.Append(DeviceAddress).ToArray();
|
||
|
protocolRequest = protocolRequest.Append(FunctionCode).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
if(ReadCount>2000){
|
||
|
ReadCount = 2000;
|
||
|
}
|
||
|
byte[] registerValues = ReadCount.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusTCP_ReadHoldingRegisters : IRequest
|
||
|
{
|
||
|
public const byte FunctionCode = 0x03;
|
||
|
|
||
|
public const ushort MessageId = 0xFF03;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort ReadCount { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress"></param>
|
||
|
/// <param name="registerAddress"></param>
|
||
|
/// <param name="readCount">Read count should be less than 125</param>
|
||
|
public ModbusTCP_ReadHoldingRegisters(byte deviceAddress,ushort registerAddress,ushort readCount){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
ReadCount = readCount;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = this.MakeModbusTCPPrefix(MessageId,6);
|
||
|
protocolRequest = protocolRequest.Append(DeviceAddress).ToArray();
|
||
|
protocolRequest = protocolRequest.Append(FunctionCode).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
if(ReadCount>125){
|
||
|
ReadCount = 125;
|
||
|
}
|
||
|
byte[] registerValues = ReadCount.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusTCP_ReadInputRegisters : IRequest
|
||
|
{
|
||
|
public const byte FunctionCode = 0x04;
|
||
|
|
||
|
public const ushort MessageId = 0xFF04;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort ReadCount { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress"></param>
|
||
|
/// <param name="registerAddress"></param>
|
||
|
/// <param name="readCount">Read count should be less than 125</param>
|
||
|
public ModbusTCP_ReadInputRegisters(byte deviceAddress,ushort registerAddress,ushort readCount){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
ReadCount = readCount;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = this.MakeModbusTCPPrefix(MessageId,6);
|
||
|
protocolRequest = protocolRequest.Append(DeviceAddress).ToArray();
|
||
|
protocolRequest = protocolRequest.Append(FunctionCode).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
if(ReadCount>125){
|
||
|
ReadCount = 125;
|
||
|
}
|
||
|
byte[] registerValues = ReadCount.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusTCP_WriteSingleCoil : IRequest
|
||
|
{
|
||
|
public const byte FunctionCode = 0x05;
|
||
|
|
||
|
public const ushort MessageId = 0xFF05;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public bool Value { set; get; }
|
||
|
|
||
|
public ModbusTCP_WriteSingleCoil(byte deviceAddress,ushort registerAddress,bool value){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
Value = value;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = this.MakeModbusTCPPrefix(MessageId,6);
|
||
|
protocolRequest = protocolRequest.Append(DeviceAddress).ToArray();
|
||
|
protocolRequest = protocolRequest.Append(FunctionCode).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
byte[] registerValues = {0x00,0x00};
|
||
|
if(Value){
|
||
|
registerValues[0]=0xFF;
|
||
|
}
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusTCP_WriteSingleHoldingRegister : IRequest
|
||
|
{
|
||
|
public const byte FunctionCode = 0x06;
|
||
|
|
||
|
public const ushort MessageId = 0xFF06;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort Value { set; get; }
|
||
|
|
||
|
public ModbusTCP_WriteSingleHoldingRegister(byte deviceAddress,ushort registerAddress,ushort value){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
Value = value;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = this.MakeModbusTCPPrefix(MessageId,6);
|
||
|
protocolRequest = protocolRequest.Append(DeviceAddress).ToArray();
|
||
|
protocolRequest = protocolRequest.Append(FunctionCode).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
byte[] registerValues = Value.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusTCP_WriteMultiCoil : IRequest{
|
||
|
public const byte FunctionCode = 0x0F;
|
||
|
|
||
|
public const ushort MessageId = 0xFF0F;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterStartAddress { set; get; }
|
||
|
public bool[] Values { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress">usual use 0x01 for device address</param>
|
||
|
/// <param name="registerStartAddress"></param>
|
||
|
/// <param name="values">Values length should be less than 2000</param>
|
||
|
public ModbusTCP_WriteMultiCoil(byte deviceAddress,ushort registerStartAddress,bool[] values){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterStartAddress = registerStartAddress;
|
||
|
Values = values;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
|
||
|
byte[] protocolRequest = {DeviceAddress,FunctionCode};
|
||
|
protocolRequest = protocolRequest.Concat(RegisterStartAddress.ToBytes()).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(((ushort)Values.Length).ToBytes()).ToArray();
|
||
|
|
||
|
//Length range should be 1-2000 0x0001-0x07D0,otherwise delete the data after 2000
|
||
|
if(Values.Length>2000){
|
||
|
bool[] SourceValues = Values;
|
||
|
Values = new bool[2000];
|
||
|
Array.Copy(Values,0,SourceValues,0,2000);
|
||
|
}
|
||
|
//bool array 2000 => byte array 250
|
||
|
byte[] valueGroup = Values.ToByteArray();
|
||
|
byte valueLength = (byte)valueGroup.Length;
|
||
|
protocolRequest = protocolRequest.Append(valueLength).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(valueGroup).ToArray();
|
||
|
byte[] protocolPrefix = this.MakeModbusTCPPrefix(MessageId,protocolRequest);
|
||
|
protocolRequest = protocolPrefix.Concat(protocolRequest).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Start write at Register start address,such as 0x03,write order by order like 0x03,0x04,0x05...,write count is the value array length
|
||
|
/// </summary>
|
||
|
public struct ModbusTCP_WriteMultiHoldingRegister : IRequest
|
||
|
{
|
||
|
public const byte FunctionCode = 0x10;
|
||
|
|
||
|
public const ushort MessageId = 0xFF10;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterStartAddress { set; get; }
|
||
|
public ushort[] Values { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress">usual use 0x01 for device address</param>
|
||
|
/// <param name="registerStartAddress"></param>
|
||
|
/// <param name="values">Values length should be less than 125</param>
|
||
|
public ModbusTCP_WriteMultiHoldingRegister(byte deviceAddress,ushort registerStartAddress,ushort[] values){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterStartAddress = registerStartAddress;
|
||
|
Values = values;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
|
||
|
byte[] protocolRequest = {DeviceAddress,FunctionCode};
|
||
|
protocolRequest = protocolRequest.Concat(RegisterStartAddress.ToBytes()).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(((ushort)Values.Length).ToBytes()).ToArray();
|
||
|
|
||
|
//Length range should be 1-125 0x0001-0x07D,otherwise delete the data after 125
|
||
|
if(Values.Length>125){
|
||
|
ushort[] SourceValues = Values;
|
||
|
Values = new ushort[125];
|
||
|
Array.Copy(Values,0,SourceValues,0,125);
|
||
|
}
|
||
|
//ushort array 125 => byte array 250
|
||
|
byte[] valueGroup = {};
|
||
|
foreach(ushort value in Values){
|
||
|
byte[] registerValues = value.ToBytes();
|
||
|
valueGroup = valueGroup.Concat(registerValues).ToArray();
|
||
|
}
|
||
|
byte valueLength = (byte)valueGroup.Length;
|
||
|
protocolRequest = protocolRequest.Append(valueLength).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(valueGroup).ToArray();
|
||
|
byte[] protocolPrefix = this.MakeModbusTCPPrefix(MessageId,protocolRequest);
|
||
|
protocolRequest = protocolPrefix.Concat(protocolRequest).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusTCP_Response : IResponse
|
||
|
{
|
||
|
public bool[] Coil { set; get; }
|
||
|
public bool[] DiscreteInput { set; get; }
|
||
|
public ushort[] HoldingRegister { set; get; }
|
||
|
public ushort[] InputRegister { set; get; }
|
||
|
public byte FunctionCode { set; get; }
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterStartAddress { set; get; }
|
||
|
public uint DataLength { set; get; }
|
||
|
|
||
|
public byte[] SourceData { set; get; }
|
||
|
public ModbusFunctionType FunctionType { set; get; }
|
||
|
|
||
|
public bool TrySetData(string protocolData, byte[] protocolBytes)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
if(protocolBytes==null && protocolBytes.Length < 10){
|
||
|
return false;
|
||
|
}
|
||
|
SourceData = protocolBytes;
|
||
|
DeviceAddress = protocolBytes[6];
|
||
|
FunctionType = (ModbusFunctionType)protocolBytes[7];
|
||
|
byte[] dataLength = new byte[4];
|
||
|
Array.Copy(protocolBytes,2,dataLength,0,4);
|
||
|
DataLength = dataLength.ToUINT();
|
||
|
if(protocolBytes.Length != DataLength+6){
|
||
|
return false;
|
||
|
}
|
||
|
//every response's start should be 0xff,because the request's start is 0xff
|
||
|
if(protocolBytes[0]==0xff){
|
||
|
switch(FunctionType){
|
||
|
case ModbusFunctionType.ReadCoil:
|
||
|
byte readCoilLength = protocolBytes[8];
|
||
|
byte[] CoilBytes = new byte[readCoilLength];
|
||
|
Array.Copy(protocolBytes,9,CoilBytes,0,readCoilLength);
|
||
|
Coil = CoilBytes.ToBoolArray();
|
||
|
return true;
|
||
|
case ModbusFunctionType.ReadDiscreteInput:
|
||
|
byte readDiscreteInputLength = protocolBytes[8];
|
||
|
byte[] DiscreteInputBytes = new byte[readDiscreteInputLength];
|
||
|
Array.Copy(protocolBytes,9,DiscreteInputBytes,0,readDiscreteInputLength);
|
||
|
DiscreteInput = DiscreteInputBytes.ToBoolArray();
|
||
|
return true;
|
||
|
case ModbusFunctionType.ReadHoldingRegisters:
|
||
|
byte readHoldingRegistersLength = protocolBytes[8];
|
||
|
byte[] HoldingRegistersBytes = new byte[readHoldingRegistersLength];
|
||
|
Array.Copy(protocolBytes,9,HoldingRegistersBytes,0,readHoldingRegistersLength);
|
||
|
HoldingRegister = HoldingRegistersBytes.ToUShortArray();
|
||
|
return true;
|
||
|
case ModbusFunctionType.ReadInputRegisters:
|
||
|
byte readInputRegistersLength = protocolBytes[8];
|
||
|
byte[] InputRegistersBytes = new byte[readInputRegistersLength];
|
||
|
Array.Copy(protocolBytes,9,InputRegistersBytes,0,readInputRegistersLength);
|
||
|
InputRegister = InputRegistersBytes.ToUShortArray();
|
||
|
return true;
|
||
|
case ModbusFunctionType.WriteSingleCoil:
|
||
|
return true;
|
||
|
case ModbusFunctionType.WriteSingleHoldingRegister:
|
||
|
return true;
|
||
|
case ModbusFunctionType.WriteMultiCoil:
|
||
|
return true;
|
||
|
case ModbusFunctionType.WriteMultiHoldingRegister:
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
catch (Exception)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
#region Modbus RTU Request and Response,Used RS-485 for Physic layer
|
||
|
public struct ModbusRTU_ReadCoils : IRequest{
|
||
|
public const byte FunctionCode = 0x01;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort ReadCount { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress"></param>
|
||
|
/// <param name="registerAddress"></param>
|
||
|
/// <param name="readCount">Read count should be less than 2000</param>
|
||
|
public ModbusRTU_ReadCoils(byte deviceAddress,ushort registerAddress,ushort readCount){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
ReadCount = readCount;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = { DeviceAddress , FunctionCode };
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
if(ReadCount>2000){
|
||
|
ReadCount = 2000;
|
||
|
}
|
||
|
byte[] registerValues = ReadCount.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(protocolRequest.CalculateCRC16Modbus().ToBytes()).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusRTU_ReadDiscreteInput : IRequest{
|
||
|
public const byte FunctionCode = 0x02;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort ReadCount { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress"></param>
|
||
|
/// <param name="registerAddress"></param>
|
||
|
/// <param name="readCount">Read count should be less than 2000</param>
|
||
|
public ModbusRTU_ReadDiscreteInput(byte deviceAddress,ushort registerAddress,ushort readCount){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
ReadCount = readCount;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = { DeviceAddress , FunctionCode };
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
if(ReadCount>2000){
|
||
|
ReadCount = 2000;
|
||
|
}
|
||
|
byte[] registerValues = ReadCount.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(protocolRequest.CalculateCRC16Modbus().ToBytes()).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusRTU_ReadHoldingRegisters : IRequest{
|
||
|
public const byte FunctionCode = 0x03;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort ReadCount { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress"></param>
|
||
|
/// <param name="registerAddress"></param>
|
||
|
/// <param name="readCount">Read count should be less than 2000</param>
|
||
|
public ModbusRTU_ReadHoldingRegisters(byte deviceAddress,ushort registerAddress,ushort readCount){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
ReadCount = readCount;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = { DeviceAddress , FunctionCode };
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
if(ReadCount>125){
|
||
|
ReadCount = 125;
|
||
|
}
|
||
|
byte[] registerValues = ReadCount.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(protocolRequest.CalculateCRC16Modbus().ToBytes()).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusRTU_ReadInputRegisters : IRequest{
|
||
|
public const byte FunctionCode = 0x04;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort ReadCount { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress"></param>
|
||
|
/// <param name="registerAddress"></param>
|
||
|
/// <param name="readCount">Read count should be less than 2000</param>
|
||
|
public ModbusRTU_ReadInputRegisters(byte deviceAddress,ushort registerAddress,ushort readCount){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
ReadCount = readCount;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = { DeviceAddress , FunctionCode };
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
if(ReadCount>125){
|
||
|
ReadCount = 125;
|
||
|
}
|
||
|
byte[] registerValues = ReadCount.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(protocolRequest.CalculateCRC16Modbus().ToBytes()).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusRTU_WriteSingleCoil : IRequest{
|
||
|
public const byte FunctionCode = 0x05;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public bool Value { set; get; }
|
||
|
|
||
|
public ModbusRTU_WriteSingleCoil(byte deviceAddress,ushort registerAddress,bool value){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
Value = value;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = { DeviceAddress , FunctionCode };
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
byte[] registerValues = {0x00,0x00};
|
||
|
if(Value){
|
||
|
registerValues[0]=0xFF;
|
||
|
}
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(protocolRequest.CalculateCRC16Modbus().ToBytes()).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusRTU_WriteSingleHoldingRegister : IRequest{
|
||
|
public const byte FunctionCode = 0x06;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterAddress { set; get; }
|
||
|
public ushort Value { set; get; }
|
||
|
|
||
|
public ModbusRTU_WriteSingleHoldingRegister(byte deviceAddress,ushort registerAddress,ushort value){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterAddress = registerAddress;
|
||
|
Value = value;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
byte[] protocolRequest = { DeviceAddress , FunctionCode };
|
||
|
protocolRequest = protocolRequest.Concat(RegisterAddress.ToBytes()).ToArray();
|
||
|
byte[] registerValues = Value.ToBytes();
|
||
|
protocolRequest = protocolRequest.Concat(registerValues).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(protocolRequest.CalculateCRC16Modbus().ToBytes()).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusRTU_WriteMultiCoil : IRequest{
|
||
|
public const byte FunctionCode = 0x0F;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterStartAddress { set; get; }
|
||
|
public bool[] Values { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress">usual use 0x01 for device address</param>
|
||
|
/// <param name="registerStartAddress"></param>
|
||
|
/// <param name="values">Values length should be less than 2000</param>
|
||
|
public ModbusRTU_WriteMultiCoil(byte deviceAddress,ushort registerStartAddress,bool[] values){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterStartAddress = registerStartAddress;
|
||
|
Values = values;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
|
||
|
byte[] protocolRequest = {DeviceAddress,FunctionCode};
|
||
|
protocolRequest = protocolRequest.Concat(RegisterStartAddress.ToBytes()).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(((ushort)Values.Length).ToBytes()).ToArray();
|
||
|
|
||
|
//Length range should be 1-2000 0x0001-0x07D0,otherwise delete the data after 2000
|
||
|
if(Values.Length>2000){
|
||
|
bool[] SourceValues = Values;
|
||
|
Values = new bool[2000];
|
||
|
Array.Copy(Values,0,SourceValues,0,2000);
|
||
|
}
|
||
|
//bool array 2000 => byte array 250
|
||
|
byte[] valueGroup = Values.ToByteArray();
|
||
|
byte valueLength = (byte)valueGroup.Length;
|
||
|
protocolRequest = protocolRequest.Append(valueLength).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(valueGroup).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(protocolRequest.CalculateCRC16Modbus().ToBytes()).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Start write at Register start address,such as 0x03,write order by order like 0x03,0x04,0x05...,write count is the value array length
|
||
|
/// </summary>
|
||
|
public struct ModbusRTU_WriteMultiHoldingRegister : IRequest
|
||
|
{
|
||
|
public const byte FunctionCode = 0x10;
|
||
|
|
||
|
public const ushort MessageId = 0xFF10;
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterStartAddress { set; get; }
|
||
|
public ushort[] Values { set; get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Construct the protocol
|
||
|
/// </summary>
|
||
|
/// <param name="deviceAddress">usual use 0x01 for device address</param>
|
||
|
/// <param name="registerStartAddress"></param>
|
||
|
/// <param name="values">Values length should be less than 125</param>
|
||
|
public ModbusRTU_WriteMultiHoldingRegister(byte deviceAddress,ushort registerStartAddress,ushort[] values){
|
||
|
DeviceAddress = deviceAddress;
|
||
|
RegisterStartAddress = registerStartAddress;
|
||
|
Values = values;
|
||
|
}
|
||
|
public byte[] ToProtocolByteData()
|
||
|
{
|
||
|
|
||
|
byte[] protocolRequest = {DeviceAddress,FunctionCode};
|
||
|
protocolRequest = protocolRequest.Concat(RegisterStartAddress.ToBytes()).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(((ushort)Values.Length).ToBytes()).ToArray();
|
||
|
|
||
|
//Length range should be 1-125 0x0001-0x07D,otherwise delete the data after 125
|
||
|
if(Values.Length>125){
|
||
|
ushort[] SourceValues = Values;
|
||
|
Values = new ushort[125];
|
||
|
Array.Copy(Values,0,SourceValues,0,125);
|
||
|
}
|
||
|
//ushort array 125 => byte array 250
|
||
|
byte[] valueGroup = {};
|
||
|
foreach(ushort value in Values){
|
||
|
byte[] registerValues = value.ToBytes();
|
||
|
valueGroup = valueGroup.Concat(registerValues).ToArray();
|
||
|
}
|
||
|
byte valueLength = (byte)valueGroup.Length;
|
||
|
protocolRequest = protocolRequest.Append(valueLength).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(valueGroup).ToArray();
|
||
|
protocolRequest = protocolRequest.Concat(protocolRequest.CalculateCRC16Modbus().ToBytes()).ToArray();
|
||
|
return protocolRequest;
|
||
|
}
|
||
|
|
||
|
public string ToProtocolData()
|
||
|
{
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct ModbusRTU_Response : IResponse
|
||
|
{
|
||
|
public bool[] Coil { set; get; }
|
||
|
public bool[] DiscreteInput { set; get; }
|
||
|
public ushort[] HoldingRegister { set; get; }
|
||
|
public ushort[] InputRegister { set; get; }
|
||
|
public byte FunctionCode { set; get; }
|
||
|
public byte DeviceAddress { set; get; }
|
||
|
public ushort RegisterStartAddress { set; get; }
|
||
|
|
||
|
public byte[] SourceData { set; get; }
|
||
|
public ModbusFunctionType FunctionType { set; get; }
|
||
|
|
||
|
public bool TrySetData(string protocolData, byte[] protocolBytes)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
if(protocolBytes==null && protocolBytes.Length < 6){
|
||
|
return false;
|
||
|
}
|
||
|
SourceData = protocolBytes;
|
||
|
DeviceAddress = protocolBytes[0];
|
||
|
FunctionCode = protocolBytes[1];
|
||
|
FunctionType = (ModbusFunctionType)protocolBytes[1];
|
||
|
|
||
|
//check crc verify is success
|
||
|
byte[] resultArray = new byte[protocolBytes.Length - 2];
|
||
|
Array.Copy(protocolBytes, 0, resultArray, 0, protocolBytes.Length - 2);
|
||
|
byte[] crcArray = new byte[2];
|
||
|
Array.Copy(protocolBytes, protocolBytes.Length - 2, crcArray, 0, 2);
|
||
|
if(resultArray.CalculateCRC16Modbus()!=crcArray.ToUShort()){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//every response's start should be 0xff,because the request's start is 0xff
|
||
|
switch(FunctionType){
|
||
|
case ModbusFunctionType.ReadCoil:
|
||
|
byte readCoilLength = protocolBytes[2];
|
||
|
byte[] CoilBytes = new byte[readCoilLength];
|
||
|
Array.Copy(protocolBytes,3,CoilBytes,0,readCoilLength);
|
||
|
Coil = CoilBytes.ToBoolArray();
|
||
|
return true;
|
||
|
case ModbusFunctionType.ReadDiscreteInput:
|
||
|
byte readDiscreteInputLength = protocolBytes[2];
|
||
|
byte[] DiscreteInputBytes = new byte[readDiscreteInputLength];
|
||
|
Array.Copy(protocolBytes,3,DiscreteInputBytes,0,readDiscreteInputLength);
|
||
|
DiscreteInput = DiscreteInputBytes.ToBoolArray();
|
||
|
return true;
|
||
|
case ModbusFunctionType.ReadHoldingRegisters:
|
||
|
byte readHoldingRegistersLength = protocolBytes[2];
|
||
|
byte[] HoldingRegistersBytes = new byte[readHoldingRegistersLength];
|
||
|
Array.Copy(protocolBytes,3,HoldingRegistersBytes,0,readHoldingRegistersLength);
|
||
|
HoldingRegister = HoldingRegistersBytes.ToUShortArray();
|
||
|
return true;
|
||
|
case ModbusFunctionType.ReadInputRegisters:
|
||
|
byte readInputRegistersLength = protocolBytes[2];
|
||
|
byte[] InputRegistersBytes = new byte[readInputRegistersLength];
|
||
|
Array.Copy(protocolBytes,3,InputRegistersBytes,0,readInputRegistersLength);
|
||
|
InputRegister = InputRegistersBytes.ToUShortArray();
|
||
|
return true;
|
||
|
case ModbusFunctionType.WriteSingleCoil:
|
||
|
return true;
|
||
|
case ModbusFunctionType.WriteSingleHoldingRegister:
|
||
|
return true;
|
||
|
case ModbusFunctionType.WriteMultiCoil:
|
||
|
return true;
|
||
|
case ModbusFunctionType.WriteMultiHoldingRegister:
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
catch (Exception)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
public enum ModbusFunctionType{
|
||
|
None = 0x00,
|
||
|
ReadCoil = 0x01,
|
||
|
ReadDiscreteInput = 0x02,
|
||
|
ReadHoldingRegisters = 0x03,
|
||
|
ReadInputRegisters = 0x04,
|
||
|
WriteSingleCoil = 0x05,
|
||
|
WriteSingleHoldingRegister = 0x06,
|
||
|
WriteMultiCoil = 0x0f,
|
||
|
WriteMultiHoldingRegister = 0x10
|
||
|
}
|
||
|
}
|