zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Hammer.js 实现移动端库事件
    使用两个队列模拟一个栈
    选择排序算法
    插入排序算法
    找出一个整形数组中第二大的数字
    双向冒泡排序算法
    求一个整形数组的最大子数组之和
    循环删除数组中元素的问题
    关于如何输出if()..else里的内容的问题
    小米2017秋招真题——电话号码分身问题(Java版)
  • 原文地址:https://www.cnblogs.com/victorbu/p/10370286.html
Copyright © 2011-2022 走看看