فهرست منبع

支持发送5.6.15.16类型的modbus 遥控遥调命令

xiuwei 4 سال پیش
والد
کامیت
b42e0d1676

+ 153 - 0
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/confirm/AbstractModbusConfirm.java

@@ -0,0 +1,153 @@
+package wei.yigulu.modbus.domain.confirm;
+
+import com.google.common.primitives.Bytes;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import wei.yigulu.modbus.domain.FunctionCode;
+import wei.yigulu.modbus.domain.ModbusPacketInterface;
+import wei.yigulu.modbus.domain.datatype.BooleanModbusDataInCoil;
+import wei.yigulu.modbus.domain.datatype.Register;
+import wei.yigulu.modbus.domain.datatype.RegisterValue;
+import wei.yigulu.modbus.domain.datatype.numeric.P_AB;
+import wei.yigulu.modbus.domain.datatype.numeric.SingleCommandCoilValue;
+import wei.yigulu.modbus.exceptiom.ModbusException;
+
+import javax.annotation.Nonnull;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @program: protocol
+ * @description: modbus的控制命令
+ * @author: xiuwei
+ * @create: 2021-04-26 16:14
+ */
+public abstract class AbstractModbusCommand implements ModbusPacketInterface {
+
+
+	public static final int R_MAX_NUM=120;
+
+	public static final int C_MAX_NUM=1968;
+
+	/**
+	 * 客户端地址 一字节
+	 */
+	@Setter
+	@Accessors(chain = true)
+	protected Integer slaveId = 01;
+
+	/**
+	 * 功能码  一字节
+	 */
+	protected FunctionCode functionCode;
+
+	/**
+	 * 下达数据的起始地址位  两字节
+	 */
+	protected Integer startAddress;
+
+	/**
+	 * 输出数据的数量  两字节  (线圈或者寄存器的数量) 两字节  15 16 有    5 6 没有
+	 */
+	protected Integer quantity;
+
+	/**
+	 * 输出数据的字节数  一字节(线圈数量*1或寄存器数量*2) 15 16 有    5 6 没有
+	 */
+	protected Integer numOfByte;
+
+	/**
+	 * 具体输出值的内容
+	 */
+	protected byte[] dataBytes;
+
+
+
+	public Integer getLength(){
+		if(functionCode==FunctionCode.WRITE_COIL){
+			return 6;
+		}else if(functionCode==FunctionCode.WRITE_REGISTER){
+			return 6;
+		}else {
+			return 7+dataBytes.length;
+		}
+	}
+
+
+	public AbstractModbusCommand setRegisters(@Nonnull Integer startAddress, @Nonnull List<RegisterValue> values) {
+		if (values.size() == 0) {
+			throw new RuntimeException("未传入具体的控制值");
+		}
+		this.startAddress = startAddress;
+		List<Register> registers = new ArrayList<>();
+		for (RegisterValue rv : values) {
+			registers.addAll(rv.getRegisters());
+		}
+		if(registers.size()>R_MAX_NUM){
+			throw new RuntimeException("传入寄存器的数量超过120个");
+		}
+		if (registers.size() > 1) {
+			functionCode = FunctionCode.WRITE_REGISTERS;
+			this.quantity = registers.size();
+			this.numOfByte = registers.size() * 2;
+			dataBytes = new byte[numOfByte];
+			for (int i = 0; i < registers.size(); i++) {
+				this.dataBytes[i * 2] = registers.get(i).getB1();
+				this.dataBytes[i * 2 + 1] = registers.get(i).getB2();
+			}
+		} else {
+			functionCode = FunctionCode.WRITE_REGISTER;
+			this.quantity = null;
+			this.numOfByte = null;
+			dataBytes = new byte[2];
+			this.dataBytes[0] = registers.get(0).getB1();
+			this.dataBytes[1] = registers.get(0).getB2();
+		}
+		return this;
+	}
+
+
+	public AbstractModbusCommand setCoils(@Nonnull Integer startAddress, @Nonnull List<Boolean> values) {
+		if (values.size() == 0) {
+			throw new RuntimeException("未传入具体的控制值");
+		}
+		if(values.size()>C_MAX_NUM){
+			throw new RuntimeException("传入线圈的数量超过1968个");
+		}
+		this.startAddress = startAddress;
+		if (values.size() == 1) {
+			functionCode = FunctionCode.WRITE_COIL;
+			this.quantity = null;
+			this.numOfByte = null;
+			dataBytes = new SingleCommandCoilValue(values.get(0)).encode();
+		} else {
+			functionCode = FunctionCode.WRITE_COILS;
+			this.quantity = values.size();
+			List<BooleanModbusDataInCoil> booleanModbusDataInCoils = BooleanModbusDataInCoil.getFormBooleanList(values);
+			this.numOfByte = booleanModbusDataInCoils.size();
+			List<Byte> byteList = new ArrayList<>();
+			booleanModbusDataInCoils.forEach(o -> o.encode(byteList));
+			this.dataBytes = Bytes.toArray(byteList);
+		}
+		return this;
+	}
+
+
+	@Override
+	public AbstractModbusCommand encode(List<Byte> bytes) throws ModbusException {
+		bytes.add((byte) (slaveId & 0xff));
+		bytes.add((byte) (functionCode.getCode() & 0xff));
+		new P_AB(BigDecimal.valueOf(startAddress)).encode(bytes);
+		if (quantity != null) {
+			new P_AB(BigDecimal.valueOf(quantity)).encode(bytes);
+		}
+		if (numOfByte != null) {
+			bytes.add((byte) (numOfByte & 0xff));
+		}
+		bytes.addAll(Bytes.asList(dataBytes));
+		return this;
+	}
+
+
+}

+ 51 - 0
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/confirm/RtuModbusCommand.java

@@ -0,0 +1,51 @@
+package wei.yigulu.modbus.domain.command;
+
+import com.google.common.primitives.Bytes;
+import wei.yigulu.modbus.domain.ModbusPacketInterface;
+import wei.yigulu.modbus.domain.datatype.numeric.P_BA;
+import wei.yigulu.modbus.domain.request.RtuModbusRequest;
+import wei.yigulu.modbus.exceptiom.ModbusException;
+import wei.yigulu.utils.CrcUtils;
+
+import java.math.BigDecimal;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * RTU的控制命令
+ *
+ * @author: xiuwei
+ * @version:
+ */
+public class RtuModbusCommand extends AbstractModbusCommand{
+
+	/**
+	 * crc 校验  两位 除去本两位 其余所有字节的校验位
+	 */
+	protected Integer crc16;
+
+	/**
+	 * 编码
+	 *
+	 * @param bytes 字节
+	 * @return
+	 */
+	@Override
+	public RtuModbusCommand encode(List<Byte> bytes) throws ModbusException {
+		super.encode(bytes);
+		this.crc16 = CrcUtils.generateCRC16(Bytes.toArray(bytes));
+		new P_BA(BigDecimal.valueOf(this.crc16)).encode(bytes);
+		return this;
+	}
+
+	/**
+	 * 解码
+	 *
+	 * @param byteBuf 字节缓冲
+	 */
+	@Override
+	public RtuModbusCommand decode(ByteBuffer byteBuf) throws ModbusException {
+		//super.decode(byteBuf);
+		return this;
+	}
+}

+ 65 - 0
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/confirm/TcpModbusCommand.java

@@ -0,0 +1,65 @@
+package wei.yigulu.modbus.domain.command;
+
+import lombok.Getter;
+import lombok.Setter;
+import wei.yigulu.modbus.domain.datatype.numeric.P_AB;
+import wei.yigulu.modbus.domain.tcpextracode.TcpExtraCode;
+import wei.yigulu.modbus.domain.tcpextracode.TransactionIdentifier;
+import wei.yigulu.modbus.exceptiom.ModbusException;
+
+import java.math.BigDecimal;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * tcp写的modbus 控制命令
+ *
+ * @author: xiuwei
+ * @version:
+ */
+
+public class TcpModbusCommand extends AbstractModbusCommand {
+	/**
+	 * tcp通讯时的前端附加码
+	 */
+	@Setter
+	@Getter
+	protected TcpExtraCode tcpExtraCode = new TcpExtraCode();
+	/**
+	 * 除去四个附加码 和两个长度字节 剩余的报文的字节个数
+	 */
+	@Setter
+	protected Integer length = 6;
+
+	/**
+	 * 设置事务标识符
+	 *
+	 * @param transactionIdentifier
+	 * @return
+	 */
+	public TcpModbusCommand setTransactionIdentifier(TransactionIdentifier transactionIdentifier) {
+		this.tcpExtraCode.setTransactionIdentifier(transactionIdentifier);
+		return this;
+	}
+
+	@Override
+	public TcpModbusCommand encode(List<Byte> bytes) throws ModbusException {
+		tcpExtraCode.encode(bytes);
+		new P_AB(BigDecimal.valueOf(super.getLength())).encode(bytes);
+		super.encode(bytes);
+		return this;
+	}
+
+
+	@Override
+	public TcpModbusCommand decode(ByteBuffer byteBuf) throws ModbusException {
+		if (byteBuf.remaining() != 12) {
+			throw new ModbusException("该帧非数据请求帧");
+		}
+		this.tcpExtraCode.decode(byteBuf);
+		this.setLength(new P_AB().decode(byteBuf).getValue().intValue());
+		//super.decode(byteBuf);
+		return this;
+	}
+
+}

+ 10 - 0
protocol-modbus/src/main/java/wei/yigulu/modbus/utils/ModbusCommandDataUtils.java

@@ -0,0 +1,10 @@
+package wei.yigulu.modbus.utils;
+
+/**
+ * modbs下达数据命令的工具类
+ *
+ * @author: xiuwei
+ * @version:
+ */
+public class ModbusCommandDataUtils {
+}

+ 39 - 0
protocol-modbus/src/test/java/TestRtuCommandMaster.java

@@ -0,0 +1,39 @@
+import lombok.extern.slf4j.Slf4j;
+import wei.yigulu.modbus.domain.FunctionCode;
+import wei.yigulu.modbus.domain.Obj4RequestRegister;
+import wei.yigulu.modbus.domain.datatype.IModbusDataType;
+import wei.yigulu.modbus.domain.datatype.ModbusDataTypeEnum;
+import wei.yigulu.modbus.domain.datatype.NumericModbusData;
+import wei.yigulu.modbus.domain.datatype.RegisterValue;
+import wei.yigulu.modbus.domain.datatype.numeric.ABCD;
+import wei.yigulu.modbus.domain.datatype.numeric.P_AB;
+import wei.yigulu.modbus.domain.synchronouswaitingroom.TcpSynchronousWaitingRoom;
+import wei.yigulu.modbus.exceptiom.ModbusException;
+import wei.yigulu.modbus.netty.ModbusTcpMasterBuilder;
+import wei.yigulu.modbus.utils.ModbusCommandDataUtils;
+import wei.yigulu.modbus.utils.ModbusRequestDataUtils;
+
+import java.math.BigDecimal;
+import java.util.*;
+
+/**
+ * @author: xiuwei
+ * @version:
+ */
+@Slf4j
+public class TestTcpCommandMaster {
+	public static void main(String[] args) throws InterruptedException, ModbusException {
+		ModbusTcpMasterBuilder master = new ModbusTcpMasterBuilder("127.0.0.1", 5002);
+		master.createByUnBlock();
+		TcpSynchronousWaitingRoom.waitTime=5000L;
+		Thread.sleep(3000L);
+		List<RegisterValue> list = new ArrayList<>();
+		for (int i = 0; i <= 0; i++) {
+			list.add(new P_AB().setValue(BigDecimal.valueOf(5)));
+		}
+		ModbusCommandDataUtils.commandRegister(master,1,0,list);
+		Thread.sleep(30L);
+		}
+
+
+}

+ 54 - 0
protocol-modbus/src/test/java/TestTcpCommandMaster.java

@@ -0,0 +1,54 @@
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import wei.yigulu.modbus.domain.FunctionCode;
+import wei.yigulu.modbus.domain.Obj4RequestRegister;
+import wei.yigulu.modbus.domain.datatype.BooleanModbusDataInRegister;
+import wei.yigulu.modbus.domain.datatype.IModbusDataType;
+import wei.yigulu.modbus.domain.datatype.ModbusDataTypeEnum;
+import wei.yigulu.modbus.domain.datatype.NumericModbusData;
+import wei.yigulu.modbus.domain.synchronouswaitingroom.SynchronousWaitingRoom;
+import wei.yigulu.modbus.domain.synchronouswaitingroom.TcpSynchronousWaitingRoom;
+import wei.yigulu.modbus.exceptiom.ModbusException;
+import wei.yigulu.modbus.netty.ModbusTcpMasterBuilder;
+import wei.yigulu.modbus.utils.ModbusRequestDataUtils;
+
+import java.util.*;
+
+/**
+ * @author: xiuwei
+ * @version:
+ */
+@Slf4j
+public class TestMaster {
+	public static void main(String[] args) throws InterruptedException, ModbusException {
+		ModbusTcpMasterBuilder master = new ModbusTcpMasterBuilder("127.0.0.1", 5001);
+		master.createByUnBlock();
+		TcpSynchronousWaitingRoom.waitTime=5000L;
+		Thread.sleep(3000L);
+		Map<Integer, ModbusDataTypeEnum> map = new HashMap<>();
+		for (int i = 0; i <= 90; i++) {
+			map.put(i , ModbusDataTypeEnum.P_AB);
+		}
+		List<Obj4RequestRegister> ll = ModbusRequestDataUtils.splitModbusRequest(map, 1, FunctionCode.READ_HOLDING_REGISTERS);
+
+		for (; ; ) {
+			try {
+				Map<Integer, IModbusDataType> map1 = ModbusRequestDataUtils.getRegisterData(master, ll);
+				ArrayList<Integer> lll = new ArrayList<Integer>(map1.keySet());
+				Collections.sort(lll);
+				for (Integer i : lll) {
+					if(map1.get(i) instanceof  NumericModbusData) {
+					//System.out.println(i + " ============ " + ((NumericModbusData) map1.get(i)).getValue());
+					}else {
+						//System.out.println(i + " ============ " + JSON.toJSONString(((BooleanModbusDataInRegister) map1.get(i)).getValues()));
+				}
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+			Thread.sleep(30L);
+		}
+
+
+	}
+}