Bladeren bron

新增modbus 线圈的读取 规定了帧类型的枚举

weiyigulu 4 jaren geleden
bovenliggende
commit
663540c05d
20 gewijzigde bestanden met toevoegingen van 537 en 138 verwijderingen
  1. 52 0
      protocol-core/src/main/java/wei/yigulu/utils/PCON.java
  2. 30 0
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/FunctionCode.java
  3. 43 15
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/ModbusSlaveDataContainer.java
  4. 45 0
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/Obj4RequestCoil.java
  5. 41 0
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/Obj4RequestData.java
  6. 46 0
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/Obj4RequestRegister.java
  7. 18 11
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/BooleanModbusDataInCoil.java
  8. 29 21
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/BooleanModbusDataInRegister.java
  9. 11 0
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/CoilValue.java
  10. 0 6
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/IModbusDataType.java
  11. 0 20
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/NumericModbusData.java
  12. 2 2
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/RegisterValue.java
  13. 4 3
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/request/AbstractModbusRequest.java
  14. 4 3
      protocol-modbus/src/main/java/wei/yigulu/modbus/domain/response/AbstractModbusResponse.java
  15. 147 47
      protocol-modbus/src/main/java/wei/yigulu/modbus/utils/ModbusRequestDataUtils.java
  16. 2 1
      protocol-modbus/src/main/java/wei/yigulu/modbus/utils/ModbusResponseDataUtils.java
  17. 4 2
      protocol-modbus/src/test/java/TestMaster.java
  18. 48 0
      protocol-modbus/src/test/java/TestMasterCoil.java
  19. 4 2
      protocol-modbus/src/test/java/TestRtuMaster.java
  20. 7 5
      protocol-modbus/src/test/java/TestSlaver.java

+ 52 - 0
protocol-core/src/main/java/wei/yigulu/utils/PCON.java

@@ -0,0 +1,52 @@
+package wei.yigulu.utils;
+
+/**
+ * 通讯协议用到的常量
+ *
+ * @author: xiuwei
+ * @version:
+ */
+public class PCON {
+
+	/**
+	 * byte中bits
+	 */
+	public static final  int BYTEBITS=8;
+
+
+	/**
+	 * 1
+	 */
+
+	public static final int ONE=1;
+
+	/**
+	 * 2
+	 */
+	public static final int TWO=2;
+
+	/**
+	 * 3
+	 */
+	public static final int THREE=3;
+
+
+	/**
+	 * 4
+	 */
+	public static final int FOUR=4;
+
+
+
+	public static final int FUNCTION_READ_COILS=1;
+
+	public static final int FUNCTION_READ_DISCRETE_INPUTS=2;
+
+	public static final int FUNCTION_READ_HOLDING_REGISTERS=3;
+
+	public static final int FUNCTION_READ_INPUT_REGISTERS=4;
+
+
+
+
+}

+ 30 - 0
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/FunctionCode.java

@@ -1,6 +1,9 @@
 package wei.yigulu.modbus.domain;
 
 import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * 功能码 copy from modbus4j
@@ -14,18 +17,22 @@ public enum FunctionCode {
 	 * Constant <code>READ_COILS 1</code>
 	 */
 	READ_COILS(1),
+	READ_COILS_ERROR(0x81),
 	/**
 	 * Constant <code>READ_DISCRETE_INPUTS 2</code>
 	 */
 	READ_DISCRETE_INPUTS(2),
+	READ_DISCRETE_INPUTS_ERROR(0x82),
 	/**
 	 * Constant <code>READ_HOLDING_REGISTERS 3</code>
 	 */
 	READ_HOLDING_REGISTERS(3),
+	READ_HOLDING_REGISTERS_ERROR(0x83),
 	/**
 	 * Constant <code>READ_INPUT_REGISTERS 4</code>
 	 */
 	READ_INPUT_REGISTERS(4),
+	READ_INPUT_REGISTERS_ERROR(0x84),
 	/**
 	 * Constant <code>WRITE_COIL 5</code>
 	 */
@@ -55,7 +62,30 @@ public enum FunctionCode {
 	 */
 	WRITE_MASK_REGISTER(22);
 
+
+	@Getter
 	private Integer code;
 
 
+	public static FunctionCode valueOf(int code){
+		switch (code){
+			case 1:return READ_COILS;
+			case 2:return READ_DISCRETE_INPUTS;
+			case 3:return READ_HOLDING_REGISTERS;
+			case 4:return READ_INPUT_REGISTERS;
+			case 0x81:return READ_COILS_ERROR;
+			case 0x82:return READ_DISCRETE_INPUTS_ERROR;
+			case 0x83:return READ_HOLDING_REGISTERS_ERROR;
+			case 0x84:return READ_INPUT_REGISTERS_ERROR;
+			case 5:return WRITE_COIL;
+			case 6:return WRITE_REGISTER;
+			case 7:return READ_EXCEPTION_STATUS;
+			case 15:return WRITE_COILS;
+			case 16:return WRITE_REGISTERS;
+			case 17:return REPORT_SLAVE_ID;
+			case 22:return WRITE_MASK_REGISTER;
+			default:throw  new IllegalArgumentException();
+		}
+
+	}
 }

+ 43 - 15
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/ModbusSlaveDataContainer.java

@@ -14,6 +14,7 @@ import wei.yigulu.modbus.domain.datatype.RegisterValue;
 import wei.yigulu.modbus.domain.datatype.numeric.P_AB;
 import wei.yigulu.modbus.domain.request.AbstractModbusRequest;
 import wei.yigulu.modbus.exceptiom.ModbusException;
+import wei.yigulu.utils.PCON;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
@@ -44,8 +45,8 @@ public class ModbusSlaveDataContainer {
 		if (byteNum == null || byteNum == 0) {
 			throw new ModbusException(3001, "请求体缺少数据个数 ");
 		}
-		Integer functionCode = abstractModbusRequest.getFunctionCode();
-		if (functionCode == null || functionCode > 4 || functionCode < 0) {
+		FunctionCode functionCode = abstractModbusRequest.getFunctionCode();
+		if (functionCode == null || functionCode.getCode() > 4 || functionCode.getCode() < 0) {
 			throw new ModbusException(3002, "不支持请求体的功能码 " + functionCode);
 		}
 		Integer position = abstractModbusRequest.getStartAddress();
@@ -57,7 +58,7 @@ public class ModbusSlaveDataContainer {
 			throw new ModbusException(3004, "请求体请求设备地址不合法 " + position);
 		}
 		if (this.slaveDataDrawer.containsKey(slaveId)) {
-			if (functionCode == 1 || functionCode == 2) {
+			if (functionCode == FunctionCode.READ_COILS || functionCode == FunctionCode.READ_DISCRETE_INPUTS) {
 				return this.slaveDataDrawer.get(slaveId).getCoilDataBytes(position, byteNum);
 			} else {
 				return this.slaveDataDrawer.get(slaveId).getRegisterDataBytes(position, byteNum);
@@ -79,6 +80,10 @@ public class ModbusSlaveDataContainer {
 		getOrCreate(slaveId).setRegister(value);
 	}
 
+	public void setCoil(int slaveId,int position,boolean value) {
+		getOrCreate(slaveId).setCoil(position,value);
+	}
+
 	private DataDrawer getOrCreate(int slave) {
 		if (!this.slaveDataDrawer.containsKey(slave)) {
 			this.slaveDataDrawer.put(slave, new DataDrawer());
@@ -91,7 +96,7 @@ public class ModbusSlaveDataContainer {
 	 */
 	private class DataDrawer {
 
-		List<CoilValue> coils = new CopyOnWriteArrayList<>();
+		List<Boolean> coils = new CopyOnWriteArrayList<>();
 
 		List<Register> registers = new CopyOnWriteArrayList<>();
 
@@ -120,21 +125,28 @@ public class ModbusSlaveDataContainer {
 			setRegister(0, value);
 		}
 
-		public void setCoil(int position, CoilValue value) {
-			if (coils.size() <= position) {
-				int num = position + 1 - coils.size();
-				for (int i = 0; i < num; i++) {
-					this.coils.add(new BooleanModbusDataInCoil());
+
+		/**
+		 * 设置线圈值
+		 *
+		 * @param position 线圈的位置  第几个线圈 从0开始
+		 * @param value    值
+		 */
+		public void setCoil(int position, boolean value) {
+			int coilsSize=this.coils.size();
+			if(coilsSize<=position){
+				for(int i=0;i<coilsSize-position+1;i++){
+					coils.add(false);
 				}
 			}
-			this.coils.set(position, value);
+			this.coils.set(position,value);
 		}
 
 
-		public byte[] getRegisterDataBytes(int position, int bitNum) {
-			List<Byte> bytes = new ArrayList<>(bitNum * 2);
+		public byte[] getRegisterDataBytes(int position, int registerNum) {
+			List<Byte> bytes = new ArrayList<>(registerNum * 2);
 			int registersSize = this.registers.size();
-			for (int i = position; i < position + bitNum; i++) {
+			for (int i = position; i < position + registerNum; i++) {
 				if (registersSize > i) {
 					bytes.add(this.registers.get(i).getB1());
 					bytes.add(this.registers.get(i).getB2());
@@ -147,8 +159,24 @@ public class ModbusSlaveDataContainer {
 		}
 
 		public byte[] getCoilDataBytes(int position, int bitNum) {
-
-			return null;
+			int coilsSize=coils.size();
+			List<Byte> bytes=new ArrayList<>();
+			byte b=0;
+			int  siftNum=0;
+			for(int i=position;i<bitNum+position;i++){
+				if(coilsSize>i && coils.get(i)){
+					b |= (0x01 <<siftNum);
+				}
+				if(++siftNum==8){
+					siftNum=0;
+					bytes.add(b);
+					b=0;
+				}
+			}
+			if(siftNum!=0){
+				bytes.add(b);
+			}
+			return Bytes.toArray(bytes);
 		}
 	}
 }

+ 45 - 0
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/Obj4RequestCoil.java

@@ -0,0 +1,45 @@
+package wei.yigulu.modbus.domain;
+
+import lombok.Getter;
+import wei.yigulu.modbus.domain.request.RtuModbusRequest;
+import wei.yigulu.modbus.domain.request.TcpModbusRequest;
+import wei.yigulu.modbus.exceptiom.ModbusException;
+import wei.yigulu.modbus.utils.ModbusRequestDataUtils;
+
+import java.util.List;
+
+/**
+ * 请求寄存器的辅助类
+ *
+ * @author: xiuwei
+ * @version:
+ */
+public class Obj4RequestCoil extends  Obj4RequestData {
+
+	@Getter
+	List<Integer> locator;
+
+	public Obj4RequestCoil(int slaveId, FunctionCode functionCode, List<Integer> locator) throws ModbusException {
+		super(slaveId, functionCode);
+		if(FunctionCode.READ_COILS!=functionCode && FunctionCode.READ_DISCRETE_INPUTS !=functionCode){
+			throw new ModbusException("该实体仅能接受1,2功能码,请求寄存器数据");
+		}
+		this.locator=locator;
+	}
+
+	@Override
+	public TcpModbusRequest getTcpModbusRequest() throws ModbusException {
+		if (this.tcpModbusRequest == null) {
+			this.tcpModbusRequest = ModbusRequestDataUtils.verifyAndCreateRequest(new TcpModbusRequest(), slaveId, functionCode, locator);
+		}
+		return this.tcpModbusRequest;
+	}
+
+	@Override
+	public RtuModbusRequest getRtuModbusRequest() throws ModbusException {
+		if(this.rtuModbusRequest ==null){
+			this.rtuModbusRequest = ModbusRequestDataUtils.verifyAndCreateRequest(new RtuModbusRequest(), slaveId, functionCode, locator);
+		}
+		return this.rtuModbusRequest;
+	}
+}

+ 41 - 0
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/Obj4RequestData.java

@@ -0,0 +1,41 @@
+package wei.yigulu.modbus.domain;
+
+import lombok.Getter;
+import wei.yigulu.modbus.domain.datatype.ModbusDataTypeEnum;
+import wei.yigulu.modbus.domain.request.RtuModbusRequest;
+import wei.yigulu.modbus.domain.request.TcpModbusRequest;
+import wei.yigulu.modbus.exceptiom.ModbusException;
+import wei.yigulu.modbus.utils.ModbusRequestDataUtils;
+import wei.yigulu.utils.PCON;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 方便请求和解析数据所构建的对象
+ * @author Administrator
+ */
+public abstract class Obj4RequestData {
+
+
+	int slaveId;
+
+	FunctionCode functionCode;
+
+	TcpModbusRequest tcpModbusRequest = null;
+
+	RtuModbusRequest rtuModbusRequest = null;
+
+
+
+	public Obj4RequestData(int slaveId, FunctionCode functionCode) {
+		this.slaveId = slaveId;
+		this.functionCode = functionCode;
+	}
+
+
+	public abstract TcpModbusRequest getTcpModbusRequest() throws ModbusException;
+
+	public abstract RtuModbusRequest getRtuModbusRequest() throws ModbusException;
+
+}

+ 46 - 0
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/Obj4RequestRegister.java

@@ -0,0 +1,46 @@
+package wei.yigulu.modbus.domain;
+
+import lombok.Getter;
+import wei.yigulu.modbus.domain.datatype.ModbusDataTypeEnum;
+import wei.yigulu.modbus.domain.request.RtuModbusRequest;
+import wei.yigulu.modbus.domain.request.TcpModbusRequest;
+import wei.yigulu.modbus.exceptiom.ModbusException;
+import wei.yigulu.modbus.utils.ModbusRequestDataUtils;
+
+import java.util.Map;
+
+/**
+ * 请求寄存器的辅助类
+ *
+ * @author: xiuwei
+ * @version:
+ */
+public class Obj4RequestRegister extends  Obj4RequestData {
+
+	@Getter
+	Map<Integer, ModbusDataTypeEnum> locator;
+
+	public Obj4RequestRegister(int slaveId, FunctionCode functionCode,Map<Integer, ModbusDataTypeEnum> locator) throws ModbusException {
+		super(slaveId, functionCode);
+		if(functionCode!=FunctionCode.READ_HOLDING_REGISTERS && functionCode !=FunctionCode.READ_INPUT_REGISTERS){
+			throw new ModbusException("该实体仅能接受3,4功能码,请求寄存器数据");
+		}
+		this.locator=locator;
+	}
+
+	@Override
+	public TcpModbusRequest getTcpModbusRequest() throws ModbusException {
+		if (this.tcpModbusRequest == null) {
+			this.tcpModbusRequest = ModbusRequestDataUtils.verifyAndCreateRequest(new TcpModbusRequest(), slaveId, functionCode, locator);
+		}
+		return this.tcpModbusRequest;
+	}
+
+	@Override
+	public RtuModbusRequest getRtuModbusRequest() throws ModbusException {
+		if(this.rtuModbusRequest ==null){
+			this.rtuModbusRequest = ModbusRequestDataUtils.verifyAndCreateRequest(new RtuModbusRequest(), slaveId, functionCode, locator);
+		}
+		return this.rtuModbusRequest;
+	}
+}

+ 18 - 11
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/BooleanModbusDataInCoil.java

@@ -13,14 +13,14 @@ import java.util.List;
 public class BooleanModbusDataInCoil extends CoilValue {
 
 	/**
-	 * 八个布尔 对应一字节 八比特
+	 * 八个布尔 对应一字节 八比特
 	 */
 	boolean[] values = new boolean[8];
 
 
 	@Override
 	public IModbusDataType decode(byte[] bytes, int offset) {
-		return getValFormByte(bytes[2 * offset]);
+		return getValFormByte(bytes[offset]);
 	}
 
 	@Override
@@ -36,15 +36,22 @@ public class BooleanModbusDataInCoil extends CoilValue {
 		return this;
 	}
 
-	@Override
-	public IModbusDataType encode(List<Byte> bytes) {
-		byte b = 0;
-		for (int i = 0; i < values.length; i++) {
-			if (this.values[i]) {
-				b |= (0x01 << i);
-			}
+
+	public void setValue(int index,boolean value){
+		if(index<values.length){
+			this.values[index]=value;
+		}else{
+			throw new IllegalArgumentException();
 		}
-		bytes.add(b);
-		return this;
 	}
+
+	public boolean getValue(int index){
+		if(index<values.length){
+			return this.values[index];
+		}else{
+			throw new IllegalArgumentException();
+		}
+	}
+
+
 }

+ 29 - 21
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/BooleanModbusDataInRegister.java

@@ -1,11 +1,11 @@
 package wei.yigulu.modbus.domain.datatype;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
- * 16个布尔值组成的数据类型
- * 仅对应 01 和 02 功能码
+ * 16个布尔值组成的数据类型 仅对应 01 和 02 功能码
  *
  * @author: xiuwei
  * @version:
@@ -13,14 +13,23 @@ import java.util.List;
 public class BooleanModbusDataInRegister extends RegisterValue {
 
 	/**
-	 * 16个bit  构成16个布尔
+	 * 一个字节存放布尔值个数
 	 */
-	boolean[] values = new boolean[16];
+	private static final int ONEBYTEBOOL = 8;
+
+	/**
+	 * 两个字节存放布尔值个数
+	 */
+	private static final int TWOBYTEBOOL = 16;
 
+	/**
+	 * 16个bit 构成16个布尔
+	 */
+	boolean[] values = new boolean[16];
 
 	@Override
 	public BooleanModbusDataInRegister decode(byte[] bytes, int offset) {
-		return getValFormByte(bytes[2 * offset], bytes[2 * offset + 1]);
+		return getValFormByte(bytes[BYTEINREGISTER * offset], bytes[BYTEINREGISTER * offset + 1]);
 	}
 
 	@Override
@@ -30,36 +39,35 @@ public class BooleanModbusDataInRegister extends RegisterValue {
 	}
 
 	private BooleanModbusDataInRegister getValFormByte(byte b1, byte b2) {
-		for (int i = 0; i < 8; i++) {
+		for (int i = 0; i < ONEBYTEBOOL; i++) {
 			this.values[i] = (byte) ((b1 >> i) & 0x01) == 0x01;
 		}
-		for (int i = 8; i < 16; i++) {
+		for (int i = ONEBYTEBOOL; i < TWOBYTEBOOL; i++) {
 			this.values[i] = (byte) ((b2 >> (i - 8)) & 0x01) == 0x01;
 		}
 		return this;
 	}
 
-	@Override
-	public BooleanModbusDataInRegister encode(List<Byte> bytes) {
-		byte b = 0;
-		for (int i = 0; i < 8; i++) {
+	/**
+	 * 入参0  即获取高位的byte
+	 * 入参1 即获取低位的byte
+	 * @param whichByte
+	 * @return
+	 */
+	private byte getByteFormValue(int whichByte){
+		byte b=0;
+		for (int i = whichByte*ONEBYTEBOOL; i < (whichByte+1)*ONEBYTEBOOL; i++) {
 			if (this.values[i]) {
 				b |= (0x01 << i);
 			}
 		}
-		bytes.add(b);
-		b = 0;
-		for (int i = 8; i < 16; i++) {
-			if (this.values[i]) {
-				b |= (0x01 << (i - 8));
-			}
-		}
-		bytes.add(b);
-		return this;
+		return b;
 	}
 
 	@Override
 	public List<Register> getRegisters() {
-		return null;
+		List<Register> registers = new ArrayList<>();
+		registers.add(new Register(getByteFormValue(0),getByteFormValue(1)));
+		return registers;
 	}
 }

+ 11 - 0
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/CoilValue.java

@@ -1,5 +1,9 @@
 package wei.yigulu.modbus.domain.datatype;
 
+import wei.yigulu.utils.PCON;
+
+import java.util.List;
+
 /**
  * @program: modbus
  * @description: 线圈值
@@ -7,4 +11,11 @@ package wei.yigulu.modbus.domain.datatype;
  * @create: 2020-08-17 16:07
  */
 public abstract class CoilValue implements IModbusDataType {
+
+
+
+
+
+
+
 }

+ 0 - 6
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/IModbusDataType.java

@@ -29,12 +29,6 @@ public interface IModbusDataType {
 	IModbusDataType decode(ByteBuffer byteBuf);
 
 
-	/**
-	 * 编码
-	 *
-	 * @param bytes 字节
-	 */
-	IModbusDataType encode(List<Byte> bytes);
 
 
 }

+ 0 - 20
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/NumericModbusData.java

@@ -28,30 +28,10 @@ public abstract class NumericModbusData extends RegisterValue {
 	protected BigDecimal value;
 
 	/**
-	 * 解码
-	 *
-	 * @param bytes  字节
-	 * @param offset 偏移量 偏移量是相对寄存器讲的
-	 */
-	@Override
-	public abstract IModbusDataType decode(byte[] bytes, int offset);
-
-	/**
-	 * 解码
-	 *
-	 * @param byteBuf 字节缓冲区
-	 * @return {@link IModbusDataType}
-	 */
-	@Override
-	public abstract IModbusDataType decode(ByteBuffer byteBuf);
-
-
-	/**
 	 * 编码
 	 *
 	 * @param bytes 字节
 	 */
-	@Override
 	public abstract IModbusDataType encode(List<Byte> bytes);
 
 }

+ 2 - 2
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/datatype/RegisterValue.java

@@ -12,10 +12,11 @@ import java.util.List;
  */
 public abstract class RegisterValue implements IModbusDataType {
 
+	protected static final int BYTEINREGISTER = 2;
+
 	@Getter
 	protected ModbusDataTypeEnum modbusDataTypeEnum = ModbusDataTypeEnum.P_AB;
 
-
 	/**
 	 * 转化成register字串
 	 *
@@ -23,5 +24,4 @@ public abstract class RegisterValue implements IModbusDataType {
 	 */
 	public abstract List<Register> getRegisters();
 
-
 }

+ 4 - 3
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/request/AbstractModbusRequest.java

@@ -3,6 +3,7 @@ package wei.yigulu.modbus.domain.request;
 
 import lombok.Data;
 import lombok.experimental.Accessors;
+import wei.yigulu.modbus.domain.FunctionCode;
 import wei.yigulu.modbus.domain.datatype.numeric.P_AB;
 import wei.yigulu.modbus.exceptiom.ModbusException;
 
@@ -29,7 +30,7 @@ public class AbstractModbusRequest {
 	/**
 	 * 功能码  一字节
 	 */
-	protected Integer functionCode = 03;
+	protected FunctionCode functionCode = FunctionCode.READ_HOLDING_REGISTERS;
 
 	/**
 	 * 请求数据的起始地址位  两字节
@@ -48,7 +49,7 @@ public class AbstractModbusRequest {
 	 */
 	public void encode(List<Byte> bytes) {
 		bytes.add((byte) (slaveId & 0xff));
-		bytes.add((byte) (functionCode & 0xff));
+		bytes.add((byte) (functionCode.getCode() & 0xff));
 		new P_AB(BigDecimal.valueOf(startAddress)).encode(bytes);
 		new P_AB(BigDecimal.valueOf(quantity)).encode(bytes);
 	}
@@ -60,7 +61,7 @@ public class AbstractModbusRequest {
 	 */
 	public AbstractModbusRequest decode(ByteBuffer byteBuf) throws ModbusException {
 		this.setSlaveId(byteBuf.get() & 0xff);
-		this.setFunctionCode(byteBuf.get() & 0xff);
+		this.setFunctionCode(FunctionCode.valueOf(byteBuf.get() & 0xff));
 		this.setStartAddress(new P_AB().decode(byteBuf).getValue().intValue());
 		this.setQuantity(new P_AB().decode(byteBuf).getValue().intValue());
 		return this;

+ 4 - 3
protocol-modbus/src/main/java/wei/yigulu/modbus/domain/response/AbstractModbusResponse.java

@@ -3,6 +3,7 @@ package wei.yigulu.modbus.domain.response;
 import com.google.common.primitives.Bytes;
 import lombok.Getter;
 import lombok.Setter;
+import wei.yigulu.modbus.domain.FunctionCode;
 import wei.yigulu.modbus.exceptiom.ModbusException;
 
 import java.nio.ByteBuffer;
@@ -27,7 +28,7 @@ public class AbstractModbusResponse {
 	/**
 	 * 功能码 1字节
 	 */
-	protected Integer functionCode;
+	protected FunctionCode functionCode;
 
 	/**
 	 * 表示数据的 字节 数量  1字节
@@ -42,7 +43,7 @@ public class AbstractModbusResponse {
 
 	public AbstractModbusResponse decode(ByteBuffer byteBuf) throws ModbusException {
 		this.slaveId = (int) byteBuf.get() & 0xff;
-		this.functionCode = (int) byteBuf.get() & 0xff;
+		this.functionCode = FunctionCode.valueOf((int) byteBuf.get() & 0xff);
 		this.dataBitNum = (int) byteBuf.get() & 0xff;
 		this.dataBytes = new byte[this.dataBitNum];
 		byteBuf.get(this.dataBytes);
@@ -51,7 +52,7 @@ public class AbstractModbusResponse {
 
 	public AbstractModbusResponse encode(List<Byte> bytes) throws ModbusException {
 		bytes.add((byte) (slaveId & 0xff));
-		bytes.add((byte) (functionCode & 0xff));
+		bytes.add((byte) (functionCode.getCode() & 0xff));
 		bytes.add((byte) (dataBytes.length & 0xff));
 		bytes.addAll(Bytes.asList(dataBytes));
 		return this;

+ 147 - 47
protocol-modbus/src/main/java/wei/yigulu/modbus/utils/ModbusRequestDataUtils.java

@@ -1,12 +1,14 @@
 package wei.yigulu.modbus.utils;
 
 import com.google.common.primitives.Bytes;
-import lombok.Getter;
 import lombok.NonNull;
+import wei.yigulu.modbus.domain.FunctionCode;
+import wei.yigulu.modbus.domain.Obj4RequestCoil;
+import wei.yigulu.modbus.domain.Obj4RequestRegister;
+import wei.yigulu.modbus.domain.datatype.BooleanModbusDataInCoil;
 import wei.yigulu.modbus.domain.datatype.IModbusDataType;
 import wei.yigulu.modbus.domain.datatype.ModbusDataTypeEnum;
 import wei.yigulu.modbus.domain.request.AbstractModbusRequest;
-import wei.yigulu.modbus.domain.request.RtuModbusRequest;
 import wei.yigulu.modbus.domain.request.TcpModbusRequest;
 import wei.yigulu.modbus.domain.response.AbstractModbusResponse;
 import wei.yigulu.modbus.domain.response.RtuModbusResponse;
@@ -16,6 +18,7 @@ import wei.yigulu.modbus.exceptiom.ModbusException;
 import wei.yigulu.modbus.netty.ModbusMasterBuilderInterface;
 import wei.yigulu.netty.AbstractMasterBuilder;
 import wei.yigulu.netty.AbstractTcpMasterBuilder;
+import wei.yigulu.utils.PCON;
 
 import java.nio.ByteBuffer;
 import java.util.*;
@@ -32,7 +35,7 @@ public class ModbusRequestDataUtils {
 
 
 	/**
-	 * 拆分map 由于modbus 每帧只能请求255个字节  125个寄存区
+	 * 拆分map 由于modbus 每帧只能请求255个字节  125个寄存区  寄存器
 	 * 所以请求数据较多时需要拆成n帧 依次请求
 	 *
 	 * @param modbusDataTypeEnumMap modbus寄存器地址 ----- modbus 对应该地址的数据类型枚举
@@ -41,15 +44,15 @@ public class ModbusRequestDataUtils {
 	 * @return Obj4RequestData     组装好的用于请求的对象
 	 * @throws ModbusException
 	 */
-	public static List<Obj4RequestData> splitModbusRequest(Map<Integer, ModbusDataTypeEnum> modbusDataTypeEnumMap, int slave, int functionCode) throws ModbusException {
-		List<Obj4RequestData> list = new ArrayList<>();
+	public static List<Obj4RequestRegister> splitModbusRequest(Map<Integer, ModbusDataTypeEnum> modbusDataTypeEnumMap, int slave, FunctionCode functionCode) throws ModbusException {
+		List<Obj4RequestRegister> list = new ArrayList<>();
 		Set<Integer> set = new TreeSet(modbusDataTypeEnumMap.keySet());
 		Integer max = Collections.max(set);
 		Integer min = Collections.min(set);
 		Map<Integer, ModbusDataTypeEnum> map = new HashMap<>();
 		int i = 1;
 		if (max + modbusDataTypeEnumMap.get(max).getOccupiedRegister() - min < MAXLENGTH) {
-			list.add(new Obj4RequestData(slave, functionCode, modbusDataTypeEnumMap));
+			list.add(new Obj4RequestRegister(slave, functionCode, modbusDataTypeEnumMap));
 			return list;
 		} else {
 			for (Integer e : set) {
@@ -57,7 +60,7 @@ public class ModbusRequestDataUtils {
 					map.put(e, modbusDataTypeEnumMap.get(e));
 				} else {
 					if (map.size() != 0) {
-						list.add(new Obj4RequestData(slave, functionCode, map));
+						list.add(new Obj4RequestRegister(slave, functionCode, map));
 						map = new HashMap<>();
 						map.put(e, modbusDataTypeEnumMap.get(e));
 					}
@@ -65,7 +68,7 @@ public class ModbusRequestDataUtils {
 				}
 			}
 			if (map.size() > 0) {
-				list.add(new Obj4RequestData(slave, functionCode, map));
+				list.add(new Obj4RequestRegister(slave, functionCode, map));
 			}
 			return list;
 		}
@@ -73,7 +76,44 @@ public class ModbusRequestDataUtils {
 
 
 	/**
-	 * 验证并创建请求对象
+	 * 拆分map 由于modbus 每帧只能请求255个字节(线圈)
+	 * 所以请求数据较多时需要拆成n帧 依次请求
+	 *
+	 * @param locator      modbus寄存器地址
+	 * @param slave        从站地址
+	 * @param functionCode 功能码
+	 * @return Obj4RequestData     组装好的用于请求的对象
+	 * @throws ModbusException
+	 */
+	public static List<Obj4RequestCoil> splitModbusRequest(List<Integer> locator, int slave, FunctionCode functionCode) throws ModbusException {
+		List<Obj4RequestCoil> list = new ArrayList<>();
+		Collections.sort(locator);
+		Integer max = locator.get(0);
+		Integer min = locator.get(locator.size() - 1);
+		List<Integer> ls = new ArrayList<>();
+		if (max - min < MAXLENGTH) {
+			list.add(new Obj4RequestCoil(slave, functionCode, locator));
+			return list;
+		} else {
+			for (Integer l : locator) {
+				if ((l - min) < 255) {
+					ls.add(l);
+				} else {
+					list.add(new Obj4RequestCoil(slave, functionCode, ls));
+					ls = new ArrayList<>();
+					ls.add(l);
+					min = l;
+				}
+			}
+			if (ls.size() > 0) {
+				list.add(new Obj4RequestCoil(slave, functionCode, ls));
+			}
+			return list;
+		}
+	}
+
+	/**
+	 * 验证并创建请求对象 寄存器数据
 	 * 验证map中的数据类型和地址位的关系是否正确
 	 * 如果验证后 关系不对将抛出异常
 	 *
@@ -81,7 +121,10 @@ public class ModbusRequestDataUtils {
 	 * @return
 	 * @throws ModbusException
 	 */
-	private static <T extends AbstractModbusRequest> T verifyAndCreateRequest(T requestType, int slaveId, int functionCode, @NonNull Map<Integer, ModbusDataTypeEnum> locator) throws ModbusException {
+	public static <T extends AbstractModbusRequest> T verifyAndCreateRequest(T requestType, int slaveId, FunctionCode functionCode, @NonNull Map<Integer, ModbusDataTypeEnum> locator) throws ModbusException {
+		if (FunctionCode.READ_HOLDING_REGISTERS != functionCode && FunctionCode.READ_INPUT_REGISTERS != functionCode) {
+			throw new ModbusException("功能码与查询类型不符");
+		}
 		Set<Integer> ketSet = new TreeSet(locator.keySet());
 		if (locator.size() == 0) {
 			return null;
@@ -107,6 +150,28 @@ public class ModbusRequestDataUtils {
 
 
 	/**
+	 * 验证并创建请求对象  线圈数据类型
+	 * 验证map中的数据类型和地址位的关系是否正确
+	 * 如果验证后 关系不对将抛出异常
+	 *
+	 * @param locator
+	 * @return
+	 * @throws ModbusException
+	 */
+	public static <T extends AbstractModbusRequest> T verifyAndCreateRequest(T requestType, int slaveId, FunctionCode functionCode, @NonNull List<Integer> locator) throws ModbusException {
+		if (FunctionCode.READ_COILS != functionCode && FunctionCode.READ_DISCRETE_INPUTS != functionCode) {
+			throw new ModbusException("功能码与查询类型不符");
+		}
+		int min = Collections.min(locator);
+		int max = Collections.max(locator);
+		if (max - min > 255) {
+			throw new ModbusException("请求的modbus数据量过多,超出长度的表达范围");
+		}
+		requestType.setStartAddress(min).setQuantity(max - min+1).setSlaveId(slaveId).setFunctionCode(functionCode);
+		return requestType;
+	}
+
+	/**
 	 * 请求数据 将请求传入后   返回modbus的响应
 	 *
 	 * @param masterBuilder master 对象
@@ -143,7 +208,25 @@ public class ModbusRequestDataUtils {
 
 
 	/**
-	 * 不了解该工具的可直接使用该方法
+	 * 不了解该工具的可直接使用该方法  寄存器
+	 * 在请求数据的发送和接收报文的基础上进行 编码和解码  编码请求报文  解码接收到的报文
+	 * 传入想要的  点位--数据类型  得到数据的map  对外暴露 逻辑上最简单的方法
+	 *
+	 * @param masterBuilder
+	 * @param locator
+	 * @param slaveId
+	 * @param functionCode
+	 * @return
+	 * @throws ModbusException
+	 */
+	public static Map<Integer, IModbusDataType> getData(AbstractMasterBuilder masterBuilder, Map<Integer, ModbusDataTypeEnum> locator, Integer slaveId, FunctionCode functionCode) throws ModbusException {
+		List<Obj4RequestRegister> list = splitModbusRequest(locator, slaveId, functionCode);
+		return getRegisterData(masterBuilder, list);
+	}
+
+
+	/**
+	 * 不了解该工具的可直接使用该方法  线圈
 	 * 在请求数据的发送和接收报文的基础上进行 编码和解码  编码请求报文  解码接收到的报文
 	 * 传入想要的  点位--数据类型  得到数据的map  对外暴露 逻辑上最简单的方法
 	 *
@@ -154,26 +237,26 @@ public class ModbusRequestDataUtils {
 	 * @return
 	 * @throws ModbusException
 	 */
-	public static Map<Integer, IModbusDataType> getData(AbstractMasterBuilder masterBuilder, Map<Integer, ModbusDataTypeEnum> locator, Integer slaveId, Integer functionCode) throws ModbusException {
-		List<Obj4RequestData> list = splitModbusRequest(locator, slaveId, functionCode);
-		return getData(masterBuilder, list);
+	public static Map<Integer, Boolean> getData(AbstractMasterBuilder masterBuilder, List<Integer> locator, Integer slaveId, FunctionCode functionCode) throws ModbusException {
+		List<Obj4RequestCoil> list = splitModbusRequest(locator, slaveId, functionCode);
+		return getCoilData(masterBuilder, list);
 	}
 
 
 	/**
-	 * 相较于上一个重载方法  这个方法适用于重复请求  如重复请求前100个数据  使用该方法
+	 * 这个方法适用于重复请求 寄存器 如重复请求前100个数据  使用该方法
 	 * 将省去系统编码的过程
 	 *
 	 * @param masterBuilder
 	 * @param locators
 	 * @return
 	 */
-	public static Map<Integer, IModbusDataType> getData(AbstractMasterBuilder masterBuilder, List<Obj4RequestData> locators) throws ModbusException {
+	public static Map<Integer, IModbusDataType> getRegisterData(AbstractMasterBuilder masterBuilder, List<Obj4RequestRegister> locators) throws ModbusException {
 		Map<Integer, IModbusDataType> map = new HashMap<>();
 		Map<Integer, IModbusDataType> map1 = null;
-		for (Obj4RequestData m : locators) {
+		AbstractModbusResponse requestData;
+		for (Obj4RequestRegister m : locators) {
 			try {
-				AbstractModbusResponse requestData;
 				if (masterBuilder instanceof AbstractTcpMasterBuilder) {
 					requestData = requestData(masterBuilder, m.getTcpModbusRequest().setTransactionIdentifier(TransactionIdentifier.getInstance((AbstractTcpMasterBuilder) masterBuilder)), new TcpModbusResponse());
 				} else {
@@ -206,40 +289,57 @@ public class ModbusRequestDataUtils {
 
 
 	/**
-	 * 方便请求和解析数据所构建的对象
+	 * 这个方法适用于重复请求 线圈 如重复请求前100个数据  使用该方法
+	 * 将省去系统编码的过程
+	 *
+	 * @param masterBuilder
+	 * @param locators
+	 * @return
 	 */
-	public static class Obj4RequestData {
-
-
-		int slaveId;
-
-		int functionCode;
-		TcpModbusRequest tcpModbusRequest = null;
-		RtuModbusRequest rtuModbusRequest = null;
-		@Getter
-		private Map<Integer, ModbusDataTypeEnum> locator;
-
-		public Obj4RequestData(int slaveId, int functionCode, Map<Integer, ModbusDataTypeEnum> locator) {
-			this.slaveId = slaveId;
-			this.functionCode = functionCode;
-			this.locator = locator;
-		}
-
-		public TcpModbusRequest getTcpModbusRequest() throws ModbusException {
-			if (this.tcpModbusRequest == null) {
-				this.tcpModbusRequest = verifyAndCreateRequest(new TcpModbusRequest(), slaveId, functionCode, locator);
+	public static Map<Integer, Boolean> getCoilData(AbstractMasterBuilder masterBuilder, List<Obj4RequestCoil> locators) throws ModbusException {
+		Map<Integer, Boolean> map = new HashMap<>();
+		Map<Integer, Boolean> map1 = null;
+		AbstractModbusResponse requestData;
+		BooleanModbusDataInCoil booleanModbusDataInCoil = new BooleanModbusDataInCoil();
+		for (Obj4RequestCoil m : locators) {
+			try {
+				if (masterBuilder instanceof AbstractTcpMasterBuilder) {
+					requestData = requestData(masterBuilder, m.getTcpModbusRequest().setTransactionIdentifier(TransactionIdentifier.getInstance((AbstractTcpMasterBuilder) masterBuilder)), new TcpModbusResponse());
+				} else {
+					requestData = requestData(masterBuilder, m.getRtuModbusRequest(), new RtuModbusResponse());
+				}
+				byte[] bytes = requestData.getDataBytes();
+				if (bytes != null && bytes.length > 0) {
+					map1 = new HashMap<>();
+					int min = Collections.min(m.getLocator());
+					int whichByteFlag = -1;
+					int index;
+					for (Integer i : m.getLocator()) {
+						index = (i - min) / PCON.BYTEBITS;
+						if (whichByteFlag != index) {
+							whichByteFlag = index;
+							booleanModbusDataInCoil = new BooleanModbusDataInCoil();
+							booleanModbusDataInCoil.decode(bytes, index);
+						}
+						map1.put(i, booleanModbusDataInCoil.getValue((i - min) % PCON.BYTEBITS));
+					}
+				}
+				if (map1 != null) {
+					map.putAll(map1);
+				}
+			} catch (ModbusException e) {
+				if ("当前并Master未链接到Salve端".equals(e.getMsg())) {
+					throw e;
+				}
+				masterBuilder.getLog().error(e.getMsg());
+			} catch (Exception e) {
+				e.printStackTrace();
 			}
-			return this.tcpModbusRequest;
 		}
+		return map;
+	}
 
-		public RtuModbusRequest getRtuModbusRequest() throws ModbusException {
-			if (this.rtuModbusRequest == null) {
-				this.rtuModbusRequest = verifyAndCreateRequest(new RtuModbusRequest(), slaveId, functionCode, locator);
-			}
-			return this.rtuModbusRequest;
-		}
 
-	}
 }
 
 

+ 2 - 1
protocol-modbus/src/main/java/wei/yigulu/modbus/utils/ModbusResponseDataUtils.java

@@ -1,6 +1,7 @@
 package wei.yigulu.modbus.utils;
 
 import com.google.common.primitives.Bytes;
+import wei.yigulu.modbus.domain.FunctionCode;
 import wei.yigulu.modbus.domain.ModbusSlaveDataContainer;
 import wei.yigulu.modbus.domain.request.AbstractModbusRequest;
 import wei.yigulu.modbus.domain.response.AbstractModbusResponse;
@@ -26,7 +27,7 @@ public class ModbusResponseDataUtils {
 			if (e.getCode() != null) {
 				if (e.getCode() == 3004) {
 					response.setSlaveId(request.getSlaveId());
-					response.setFunctionCode(request.getFunctionCode() + 0x80);
+					response.setFunctionCode(FunctionCode.valueOf(request.getFunctionCode().getCode()+ 0x80));
 					response.setDataBitNum(0x01);
 				}
 			}

+ 4 - 2
protocol-modbus/src/test/java/TestMaster.java

@@ -1,4 +1,6 @@
 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;
@@ -26,11 +28,11 @@ public class TestMaster {
 		for (int i = 0; i <= 7; i++) {
 			map.put(i * 2, ModbusDataTypeEnum.P_CDAB);
 		}
-		List<ModbusRequestDataUtils.Obj4RequestData> ll = ModbusRequestDataUtils.splitModbusRequest(map, 1, 3);
+		List<Obj4RequestRegister> ll = ModbusRequestDataUtils.splitModbusRequest(map, 1, FunctionCode.READ_HOLDING_REGISTERS);
 
 		for (; ; ) {
 			try {
-				Map<Integer, IModbusDataType> map1 = ModbusRequestDataUtils.getData(master, ll);
+				Map<Integer, IModbusDataType> map1 = ModbusRequestDataUtils.getRegisterData(master, ll);
 				for (Integer i : map1.keySet()) {
 					System.out.println(i + " ============ " + ((NumericModbusData) map1.get(i)).getValue());
 				}

+ 48 - 0
protocol-modbus/src/test/java/TestMasterCoil.java

@@ -0,0 +1,48 @@
+import lombok.extern.slf4j.Slf4j;
+import wei.yigulu.modbus.domain.FunctionCode;
+import wei.yigulu.modbus.domain.Obj4RequestCoil;
+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.exceptiom.ModbusException;
+import wei.yigulu.modbus.netty.ModbusTcpMasterBuilder;
+import wei.yigulu.modbus.utils.ModbusRequestDataUtils;
+
+import java.util.*;
+
+/**
+ * @author: xiuwei
+ * @version:
+ */
+@Slf4j
+public class TestMasterCoil {
+	public static void main(String[] args) throws InterruptedException, ModbusException {
+
+
+		ModbusTcpMasterBuilder master = new ModbusTcpMasterBuilder("127.0.0.1", 502);
+		master.createByUnBlock();
+		Thread.sleep(3000L);
+		List<Integer> list=new ArrayList<>();
+		for (int i = 0; i <=19; i++) {
+			list.add(i*2 );
+		}
+		List<Obj4RequestCoil> ll = ModbusRequestDataUtils.splitModbusRequest(list, 1, FunctionCode.READ_COILS);
+
+		for (; ; ) {
+			try {
+				Map<Integer, Boolean> map1 = ModbusRequestDataUtils.getCoilData(master, ll);
+				ArrayList<Integer> lll = new ArrayList<Integer>(map1.keySet());
+				Collections.sort(lll);
+				for (Integer i : lll) {
+					System.out.println(i + " ============ " + map1.get(i));
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+			Thread.sleep(3000L);
+		}
+
+
+	}
+}

+ 4 - 2
protocol-modbus/src/test/java/TestRtuMaster.java

@@ -1,4 +1,6 @@
 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;
@@ -31,11 +33,11 @@ public class TestRtuMaster {
 		for (int i = 0; i <= 30; i++) {
 			map.put(i * 2, ModbusDataTypeEnum.ABCD);
 		}
-		List<ModbusRequestDataUtils.Obj4RequestData> ll = ModbusRequestDataUtils.splitModbusRequest(map, 1, 3);
+		List<Obj4RequestRegister> ll = ModbusRequestDataUtils.splitModbusRequest(map, 1, FunctionCode.READ_HOLDING_REGISTERS);
 
 		for (; ; ) {
 			try {
-				Map<Integer, IModbusDataType> map1 = ModbusRequestDataUtils.getData(master, ll);
+				Map<Integer, IModbusDataType> map1 = ModbusRequestDataUtils.getRegisterData(master, ll);
 				for (Integer i : map1.keySet()) {
 					System.out.println(i + " ============ " + ((NumericModbusData) map1.get(i)).getValue());
 				}

+ 7 - 5
protocol-modbus/src/test/java/TestSlaver.java

@@ -1,7 +1,5 @@
-import wei.yigulu.modbus.domain.datatype.numeric.ABCD;
 import wei.yigulu.modbus.netty.ModbusTcpSlaverBuilder;
 
-import java.math.BigDecimal;
 import java.util.Random;
 
 /**
@@ -10,15 +8,19 @@ import java.util.Random;
  */
 public class TestSlaver {
 	public static void main(String[] args) throws InterruptedException {
-		ModbusTcpSlaverBuilder slaverBuilder = new ModbusTcpSlaverBuilder(2409);
+		ModbusTcpSlaverBuilder slaverBuilder = new ModbusTcpSlaverBuilder(502);
 		slaverBuilder.createByUnBlock();
 
 		Random random = new Random();
+		boolean f;
 		for (; ; ) {
 			for (int i = 0; i < 10; i++) {
-				slaverBuilder.getModbusSlaveDataContainer().setRegister(1, i, new ABCD(BigDecimal.valueOf((0.5 - random.nextDouble()) * 100)));
+				//slaverBuilder.getModbusSlaveDataContainer().setRegister(1, i, new ABCD(BigDecimal.valueOf((0.5 - random.nextDouble()) * 100)));
+				f = random.nextBoolean();
+				System.out.println(i + ":" + f);
+				slaverBuilder.getModbusSlaveDataContainer().setCoil(1, i, f);
 			}
-			Thread.sleep(200L);
+			Thread.sleep(2000L);
 		}
 	}
 }