1. 程式人生 > >DotNetty 實現 Modbus TCP 系列 (二) ModbusFunction 類圖及繼承舉例

DotNetty 實現 Modbus TCP 系列 (二) ModbusFunction 類圖及繼承舉例

說明 multiple var input ole ons orb .com 根據

本文已收錄至:開源 DotNetty 實現的 Modbus TCP/IP 協議

ModbusFunction 類圖如下:

技術分享圖片

如前文所述,所有請求/相應的 PDU 均繼承自 ModbusFunction,其子類傳入對應的 Function Code 並實現三個方法:

  1. CalculateLength:Data 部分的長度(該方法也可以為屬性,但屬性沒有強制性,怕漏掉故改為抽象方法)
  2. Decode:從緩沖區解析 Data
  3. Encode:在傳輸前對 Data 編碼

實現舉例

每個 Function Code 均對應 ModbusFunction 的兩個子類:請求類和響應類,以 0x03(讀取保持寄存器值)為例:

請求類

請求報文 Data 說明:

技術分享圖片

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 說明:

技術分享圖片

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

DotNetty 實現 Modbus TCP 系列 (二) ModbusFunction 類圖及繼承舉例