|
@@ -0,0 +1,236 @@
|
|
|
+package tunnelworker.masters.iml;
|
|
|
+
|
|
|
+
|
|
|
+import container.ProtocolDataContainer;
|
|
|
+import entity.BaseTunnelInfo;
|
|
|
+import entity.datapoint.CommandDataPoint;
|
|
|
+import entity.datapoint.GatherDataPoint;
|
|
|
+import exception.DataExchangeException;
|
|
|
+import lombok.Getter;
|
|
|
+import lombok.Setter;
|
|
|
+import tunnelworker.BaseProtocolTunnel;
|
|
|
+import tunnelworker.masters.MasterInterface;
|
|
|
+import wei.yigulu.modbus.domain.FunctionCode;
|
|
|
+import wei.yigulu.modbus.domain.Obj4RequestCoil;
|
|
|
+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.exceptiom.ModbusException;
|
|
|
+import wei.yigulu.modbus.utils.ModbusCommandDataUtils;
|
|
|
+import wei.yigulu.modbus.utils.ModbusRequestDataUtils;
|
|
|
+import wei.yigulu.netty.AbstractMasterBuilder;
|
|
|
+import wei.yigulu.netty.BaseProtocolBuilder;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+import static wei.yigulu.modbus.domain.FunctionCode.WRITE_REGISTER;
|
|
|
+
|
|
|
+/**
|
|
|
+ * modbus数据处理的基类
|
|
|
+ *
|
|
|
+ * @author: xiuwei
|
|
|
+ * @version:
|
|
|
+ */
|
|
|
+@Getter
|
|
|
+@Setter
|
|
|
+public abstract class BaseModbusMaster<T extends BaseTunnelInfo, E extends BaseProtocolBuilder> extends BaseProtocolTunnel<T, E> implements MasterInterface {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通道点位 ---- 寄存器 功能码3 点位对象
|
|
|
+ */
|
|
|
+ private Map<Integer, GatherDataPoint> r3DataPointMap;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通道点位 ---- 寄存器 功能码4 点位对象
|
|
|
+ */
|
|
|
+ private Map<Integer, GatherDataPoint> r4DataPointMap;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通道点位 ---- 线圈 功能码1 点位对象
|
|
|
+ */
|
|
|
+ private Map<Integer, GatherDataPoint> c1DataPointMap;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通道点位 ---- 线圈 功能码2 点位对象
|
|
|
+ */
|
|
|
+ private Map<Integer, GatherDataPoint> c2DataPointMap;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 向modbus slave 功能码3 端发送的请求
|
|
|
+ */
|
|
|
+ private List<Obj4RequestRegister> requestRegister3List;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 向modbus slave 功能码4 端发送的请求
|
|
|
+ */
|
|
|
+ private List<Obj4RequestRegister> requestRegister4List;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 向modbus slave 功能码1 端发送线圈的请求
|
|
|
+ */
|
|
|
+ private List<Obj4RequestCoil> requestCoil1List;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 向modbus slave 功能码2 端发送线圈的请求
|
|
|
+ */
|
|
|
+ private List<Obj4RequestCoil> requestCoil2List;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设备地址
|
|
|
+ */
|
|
|
+ private Integer slaveId = 1;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 顶层的构造方法
|
|
|
+ *
|
|
|
+ * @param tunnelInfo 通道信息
|
|
|
+ */
|
|
|
+ public BaseModbusMaster(T tunnelInfo) {
|
|
|
+ super(tunnelInfo);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void parseDataPoint() throws DataExchangeException {
|
|
|
+ log.info("解析该通道下所管理的点位");
|
|
|
+ List<GatherDataPoint> dataPoints = this.tunnelInfo.getDataPoints();
|
|
|
+ if (dataPoints == null || dataPoints.size() == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Map<Integer, ModbusDataTypeEnum> r3Points = new HashMap<>();
|
|
|
+ Map<Integer, ModbusDataTypeEnum> r4Points = new HashMap<>();
|
|
|
+ List<Integer> coil1Points = new ArrayList<>();
|
|
|
+ List<Integer> coil2Points = new ArrayList<>();
|
|
|
+ this.r3DataPointMap = new HashMap<>();
|
|
|
+ this.r4DataPointMap = new HashMap<>();
|
|
|
+ this.c1DataPointMap = new HashMap<>();
|
|
|
+ this.c2DataPointMap = new HashMap<>();
|
|
|
+ for (GatherDataPoint d : dataPoints) {
|
|
|
+ if (d.getFunctionCode() == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ switch (d.getFunctionCode()) {
|
|
|
+ case 1:
|
|
|
+ this.c1DataPointMap.put(d.getProtocolPoint(), d);
|
|
|
+ coil1Points.add(d.getProtocolPoint());
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ this.c2DataPointMap.put(d.getProtocolPoint(), d);
|
|
|
+ coil2Points.add(d.getProtocolPoint());
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ this.r3DataPointMap.put(d.getProtocolPoint(), d);
|
|
|
+ r3Points.put(d.getProtocolPoint(), d.getDataType().getModbusDataType());
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ this.r4DataPointMap.put(d.getProtocolPoint(), d);
|
|
|
+ r4Points.put(d.getProtocolPoint(), d.getDataType().getModbusDataType());
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw new DataExchangeException("Modbus 仅能采集功能码为1,2,3,4的数据");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (this.c1DataPointMap.size() > 0) {
|
|
|
+ this.requestCoil1List = ModbusRequestDataUtils.splitModbusRequest(coil1Points, getSlaveId(), FunctionCode.valueOf(1));
|
|
|
+ }
|
|
|
+ if (this.c2DataPointMap != null && this.c2DataPointMap.size() > 0) {
|
|
|
+ this.requestCoil2List = ModbusRequestDataUtils.splitModbusRequest(coil2Points, getSlaveId(), FunctionCode.valueOf(2));
|
|
|
+ }
|
|
|
+ if (this.r3DataPointMap != null && this.r3DataPointMap.size() > 0) {
|
|
|
+ this.requestRegister3List = ModbusRequestDataUtils.splitModbusRequest(r3Points, getSlaveId(), FunctionCode.valueOf(3));
|
|
|
+ }
|
|
|
+ if (this.r4DataPointMap != null && this.r4DataPointMap.size() > 0) {
|
|
|
+ this.requestRegister4List = ModbusRequestDataUtils.splitModbusRequest(r4Points, getSlaveId(), FunctionCode.valueOf(4));
|
|
|
+ }
|
|
|
+ } catch (ModbusException e) {
|
|
|
+ throw new DataExchangeException(e.getCode(), e.getMsg());
|
|
|
+ }
|
|
|
+ log.info("解析该通道下所管理的点位完成");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean sendCommand(CommandDataPoint dataPoint, Object val) throws DataExchangeException, ModbusException {
|
|
|
+ log.debug("通道{}发送控制命令,命令类型{},控制值{}",tunnelInfo.getTunnelName(),dataPoint.getCommandProtocolType().getExplain(),val);
|
|
|
+ log.debug("当下通道状态:{}",getTunnelStatus());
|
|
|
+ IModbusDataType c = dataPoint.getDataType().getModbusDataType().getObject();
|
|
|
+ switch (dataPoint.getCommandProtocolType()) {
|
|
|
+ case WRITE_REGISTER:
|
|
|
+ if (c instanceof NumericModbusData) {
|
|
|
+ return ModbusCommandDataUtils.commandRegister((wei.yigulu.netty.MasterInterface) this.protocolBuilder, this.slaveId, dataPoint.getProtocolPoint(), ((NumericModbusData) c).setValue(((BigDecimal) val).multiply(dataPoint.getRatio())));
|
|
|
+ } else {
|
|
|
+ BooleanModbusDataInRegister b = new BooleanModbusDataInRegister();
|
|
|
+ b.setValue(0, (Boolean) val);
|
|
|
+ return ModbusCommandDataUtils.commandRegister((wei.yigulu.netty.MasterInterface) this.protocolBuilder, this.slaveId, dataPoint.getProtocolPoint(), b);
|
|
|
+ }
|
|
|
+ case WRITE_COIL:
|
|
|
+ return ModbusCommandDataUtils.commandCoil((wei.yigulu.netty.MasterInterface) this.protocolBuilder, this.slaveId, dataPoint.getProtocolPoint(), (Boolean) val);
|
|
|
+ default:
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void getData() throws DataExchangeException {
|
|
|
+ log.info("获取到从通道中获取的点位");
|
|
|
+ try {
|
|
|
+ extractRegisterData(r3DataPointMap, requestRegister3List);
|
|
|
+ extractRegisterData(r4DataPointMap, requestRegister4List);
|
|
|
+ extractCoilData(c2DataPointMap, requestCoil2List);
|
|
|
+ extractCoilData(c1DataPointMap, requestCoil1List);
|
|
|
+ } catch (ModbusException e) {
|
|
|
+ throw new DataExchangeException(e.getCode(), e.getMsg());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 提取寄存器数据
|
|
|
+ *
|
|
|
+ * @param rDataPointMap 数据点映射
|
|
|
+ * @param requestRegisterList 请求寄存器列表
|
|
|
+ * @throws ModbusException modbus例外
|
|
|
+ */
|
|
|
+ private void extractRegisterData(Map<Integer, GatherDataPoint> rDataPointMap, List<Obj4RequestRegister> requestRegisterList) throws ModbusException {
|
|
|
+ if (requestRegisterList != null) {
|
|
|
+ Map<Integer, IModbusDataType> map = ModbusRequestDataUtils.getRegisterData((AbstractMasterBuilder) this.protocolBuilder, requestRegisterList);
|
|
|
+ for (Map.Entry<Integer, IModbusDataType> i : map.entrySet()) {
|
|
|
+ if (i.getValue() instanceof NumericModbusData) {
|
|
|
+ ProtocolDataContainer.getInstance().putGNumber(rDataPointMap.get(i.getKey()).getId(), ((NumericModbusData) i.getValue()).getValue().multiply(rDataPointMap.get(i.getKey()).getRatio()));
|
|
|
+ } else {
|
|
|
+ ProtocolDataContainer.getInstance().putGBoolean(rDataPointMap.get(i.getKey()).getId(), ((BooleanModbusDataInRegister) i.getValue()).getValue(0));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 提取线圈数据
|
|
|
+ *
|
|
|
+ * @param cDataPointMap 数据点映射
|
|
|
+ * @param requestCoilList 请求线圈列表
|
|
|
+ * @throws ModbusException modbus例外
|
|
|
+ */
|
|
|
+ private void extractCoilData(Map<Integer, GatherDataPoint> cDataPointMap, List<Obj4RequestCoil> requestCoilList) throws ModbusException {
|
|
|
+ if (requestCoilList != null) {
|
|
|
+ Map<Integer, Boolean> map = ModbusRequestDataUtils.getCoilData((AbstractMasterBuilder) this.protocolBuilder, requestCoilList);
|
|
|
+ for (Map.Entry<Integer, Boolean> i : map.entrySet()) {
|
|
|
+ ProtocolDataContainer.getInstance().putGBoolean(cDataPointMap.get(i.getKey()).getId(), i.getValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|