DotNetty 实现 Modbus TCP 系列 (二) ModbusFunction 类图及继承举例

本文已收录至:开源 DotNetty 实现的 Modbus TCP/IP 协议

ModbusFunction 类图如下:

Function

如前文所述,所有请求/相应的 PDU 均继承自 ModbusFunction,其子类传入对应的 Function Code 并实现三个方法:

  1. CalculateLength:Data 部分的长度(该方法也可以为属性,但属性没有强制性,怕漏掉故改为抽象方法)
  2. Decode:从缓冲区解析 Data
  3. Encode:在传输前对 Data 编码

实现举例

每个 Function Code 均对应 ModbusFunction 的两个子类:请求类和响应类,以 0x03(读取保持寄存器值)为例:

请求类

请求报文 Data 说明:

Request

public class ReadHoldingRegistersRequest : ModbusFunction
{
	public ushort StartingAddress { get; private set; }
	public ushort Quantity { get; private set; }

	public ReadHoldingRegistersRequest()
		: base((short)ModbusCommand.ReadHoldingRegisters)
	{

	}

	public ReadHoldingRegistersRequest(ushort startingAddress, ushort quantity)
		: base((short)ModbusCommand.ReadHoldingRegisters)
	{
		StartingAddress = startingAddress;
		Quantity = quantity;
	}

	public override int CalculateLength()
	{
		return 2 + 2; // StartingAddress Length + Quantity Length
	}
	public override void Decode(IByteBuffer buffer)
	{
		StartingAddress = buffer.ReadUnsignedShort();
		Quantity = buffer.ReadUnsignedShort();
	}
	public override IByteBuffer Encode()
	{
		IByteBuffer buffer = Unpooled.Buffer();
		buffer.WriteByte(FunctionCode);

		buffer.WriteUnsignedShort(StartingAddress);
		buffer.WriteUnsignedShort(Quantity);

		return buffer;
	}
}

响应类

响应报文 Data 说明:

Response

public class ReadHoldingRegistersResponse : ModbusFunction
{
	private ushort byteCount;
	public ushort[] Registers { get; private set; }

	public ReadHoldingRegistersResponse()
		: base((short)ModbusCommand.ReadHoldingRegisters)
	{

	}

	public ReadHoldingRegistersResponse(ushort[] registers)
		: base((short)ModbusCommand.ReadHoldingRegisters)
	{
		Registers = registers;
		byteCount = (ushort)(registers.Length * 2);
	}

	public override int CalculateLength()
	{
		return 1 + byteCount;
	}

	public override void Decode(IByteBuffer buffer)
	{
		byteCount = buffer.ReadByte();
		Registers = new ushort[byteCount / 2];
		for (int i = 0; i < Registers.Length; i++)
		{
			Registers[i] = buffer.ReadUnsignedShort();
		}

	}

	public override IByteBuffer Encode()
	{
		IByteBuffer buffer = Unpooled.Buffer();
		buffer.WriteByte(FunctionCode);
		buffer.WriteByte(byteCount);

		foreach (var register in Registers)
		{
			buffer.WriteUnsignedShort(register);
		}

		return buffer;
	}
}

其中 ModbusCommand 为 Function Code 的枚举:

enum ModbusCommand : short
{

	ReadCoils = 0x01,
	ReadDiscreteInputs = 0x02,
	ReadHoldingRegisters = 0x03,
	ReadInputRegisters = 0x04,
	WriteSingleCoil = 0x05,
	WriteSingleRegister = 0x06,

	WriteMultipleCoils = 0x0F,
	WriteMultipleRegisters = 0x10,

}

文中为方便理解请求类和响应类均直接继承 ModbusFunction,实际开发中请求类和响应类均没有直接继承 ModbusFunction,而是根据其他 Function Code 的 Data 进行再次抽象后继承。

开源地址:modbus-tcp

posted @ 2019-02-13 16:00  VictorBu  阅读(2205)  评论(1编辑  收藏  举报