diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/impl/DiActHeaterTokyGteModbusRtuOverTcp.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/impl/DiActHeaterTokyGteModbusRtuOverTcp.java index b6b8b4c..c3d4acb 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/impl/DiActHeaterTokyGteModbusRtuOverTcp.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/impl/DiActHeaterTokyGteModbusRtuOverTcp.java @@ -3,12 +3,19 @@ import com.my.graphiteDigesterBg.diframe.DiActuatorBase; import com.my.graphiteDigesterBg.diframe.actuator.DiActHeater; import java.io.*; import java.net.Socket; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; - +import java.util.Map; public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implements DiActHeater { + // connection + private static class Connection { + public Socket socket; + public DataOutputStream writer; + public InputStream reader; + public Boolean isBusy; + } + // host private String host; // port @@ -17,12 +24,17 @@ public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implement private Integer slaveId; // heater key private String ioKey; - // connection - private Socket connection; - // writer - private DataOutputStream writer; - // reader - private InputStream reader; + // connections + private static final Map connections = new HashMap<>(); + + // get connection + private Connection getConnection() { + String key = this.host + ":" + this.port; + if ( connections.containsKey(key) ) { + return connections.get(key); + } + return null; + } @Override public void setEnable( Boolean enable ) { @@ -35,45 +47,50 @@ public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implement @Override protected void onEnable() { - if ( null != this.connection ) { + var con = this.getConnection(); + if ( null != con ) { + LOG.info("[Actuator {}({})] {} enable -- OK", this.key, this.type, this.name); return ; } + con = new Connection(); + con.isBusy = false; try { - this.connection = new Socket(this.host, this.port); + con.socket = new Socket(this.host, this.port); } catch (IOException e) { throw new RuntimeException(e); } try { - this.writer = new DataOutputStream(this.connection.getOutputStream()); + con.writer = new DataOutputStream(con.socket.getOutputStream()); } catch (IOException e) { throw new RuntimeException(e); } try { - this.reader = this.connection.getInputStream(); + con.reader = con.socket.getInputStream(); } catch (IOException e) { throw new RuntimeException(e); } + String key = this.host + ":" + this.port; + connections.put(key, con); LOG.info("[Actuator {}({})] {} enable -- OK", this.key, this.type, this.name); } @Override protected void onDisable() { - if ( null == this.connection ) { + var con = this.getConnection(); + if ( null == con ) { + LOG.info("[Actuator {}({})] {} disable -- OK", this.key, this.type, this.name); return ; } try { - this.connection.close(); - this.connection = null; - } catch (IOException e) { - throw new RuntimeException(e); - } - try { - this.writer.close(); + con.writer.close(); + con.reader.close(); + con.socket.close(); + connections.remove(this.host + ":" + this.port); } catch (IOException e) { throw new RuntimeException(e); } @@ -103,12 +120,11 @@ public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implement cmd[3] = 0x00; // address low cmd[4] = (byte)(temperature >> 8); // value high cmd[5] = (byte)(temperature & 0xFF); // value low - this.writeCmd(cmd); - this.readCmdResponse(); + this.call(cmd); LOG.info("[Actuator {}({})] {} set temperature : {}", this.key, this.type, this.name, temperature); } - // get temperature + @Override public Integer getTemperature() { byte[] cmd = new byte[8]; cmd[0] = (byte)(this.slaveId & 0xFF); // slave id @@ -117,71 +133,99 @@ public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implement cmd[3] = 0x10; // address low cmd[4] = 0x00; // length high cmd[5] = 0x01; // length low - this.writeCmd(cmd); - var response = this.readCmdResponse(); - Integer temperature = response.get(3) << 8 | response.get(4); + var response = this.call(cmd); + + int temperature = 0; + if (!response.isEmpty()) { + temperature = response.get(3) << 8 | response.get(4); + } LOG.info("[Actuator {}({})] {} get temperature : {}", this.key, this.type, this.name, temperature); return temperature; } - /** - * 计算输入数据的CRC16 (Modbus) - * @param data 要计算CRC的字节数组 - * @param length 数组中需要计算的长度 - * @return 计算出的CRC16值 - */ - public int calculateCRC(byte[] data, int length) { - int crc = 0xFFFF; // CRC的初始值 + // call + private List call( byte[] cmd ) { + var con = this.getConnection(); + if ( null == con ) { + throw new RuntimeException("加热器"+this.key+"未启用"); + } - for (int pos = 0; pos < length; pos++) { - crc ^= data[pos] & 0xFF; // 将数据与CRC寄存器异或 - for (int i = 8; i != 0; i--) { // 循环处理每个位 - if ((crc & 0x0001) != 0) { - crc >>= 1; - crc ^= 0xA001; // 0xA001是预设的多项式 - } else { - crc >>= 1; + if ( con.isBusy ) { + synchronized ( con ) { + try { + con.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); } } } - // 高低位不交换,直接返回 - return crc & 0xFFFF; + con.isBusy = true; + this.writeCmd(con, cmd); + List response = this.readCmdResponse(con); + con.isBusy = false; + synchronized ( con ) { + con.notify(); + } + return response; } // write command - private void writeCmd( byte[] cmd ) { - if ( null == this.connection ) { - throw new RuntimeException("加热器"+this.key+"未启用"); - } - + private void writeCmd( Connection con, byte[] cmd ) { var size = cmd.length; var crc = this.calculateCRC(cmd, size - 2); cmd[size-2] = (byte)(crc & 0xFF); cmd[size-1] = (byte)(crc >> 8); try { - this.writer.write(cmd); - this.writer.flush(); + con.writer.write(cmd); + con.writer.flush(); } catch (IOException e) { throw new RuntimeException(e); } - } - // read command response - private List readCmdResponse () { - if ( null == this.connection ) { - throw new RuntimeException("加热器"+this.key+"未启用"); + try { + Thread.sleep(300); + } catch (InterruptedException e) { + throw new RuntimeException(e); } + } + // read command response + private List readCmdResponse ( Connection con ) { try { List result = new ArrayList<>(); - while ( 0 < this.reader.available() ) { - result.add(this.reader.read()); + while ( 0 < con.reader.available() ) { + result.add(con.reader.read()); } return result; } catch (IOException e) { throw new RuntimeException(e); } } + + /** + * 计算输入数据的CRC16 (Modbus) + * @param data 要计算CRC的字节数组 + * @param length 数组中需要计算的长度 + * @return 计算出的CRC16值 + */ + public int calculateCRC(byte[] data, int length) { + int crc = 0xFFFF; // CRC的初始值 + + for (int pos = 0; pos < length; pos++) { + crc ^= data[pos] & 0xFF; // 将数据与CRC寄存器异或 + for (int i = 8; i != 0; i--) { // 循环处理每个位 + if ((crc & 0x0001) != 0) { + crc >>= 1; + crc ^= 0xA001; // 0xA001是预设的多项式 + } else { + crc >>= 1; + } + } + } + + // 高低位不交换,直接返回 + return crc & 0xFFFF; + } }