唐山轨道机控制端TCP服务
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.

838 lines
34 KiB

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