|
@ -3,12 +3,19 @@ import com.my.graphiteDigesterBg.diframe.DiActuatorBase; |
|
|
import com.my.graphiteDigesterBg.diframe.actuator.DiActHeater; |
|
|
import com.my.graphiteDigesterBg.diframe.actuator.DiActHeater; |
|
|
import java.io.*; |
|
|
import java.io.*; |
|
|
import java.net.Socket; |
|
|
import java.net.Socket; |
|
|
import java.nio.ByteBuffer; |
|
|
|
|
|
import java.nio.ByteOrder; |
|
|
|
|
|
import java.util.ArrayList; |
|
|
import java.util.ArrayList; |
|
|
|
|
|
import java.util.HashMap; |
|
|
import java.util.List; |
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
import java.util.Map; |
|
|
public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implements DiActHeater { |
|
|
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 |
|
|
// host |
|
|
private String host; |
|
|
private String host; |
|
|
// port |
|
|
// port |
|
@ -17,12 +24,17 @@ public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implement |
|
|
private Integer slaveId; |
|
|
private Integer slaveId; |
|
|
// heater key |
|
|
// heater key |
|
|
private String ioKey; |
|
|
private String ioKey; |
|
|
// connection |
|
|
|
|
|
private Socket connection; |
|
|
|
|
|
// writer |
|
|
|
|
|
private DataOutputStream writer; |
|
|
|
|
|
// reader |
|
|
|
|
|
private InputStream reader; |
|
|
|
|
|
|
|
|
// connections |
|
|
|
|
|
private static final Map<String, Connection> 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 |
|
|
@Override |
|
|
public void setEnable( Boolean enable ) { |
|
|
public void setEnable( Boolean enable ) { |
|
@ -35,45 +47,50 @@ public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implement |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
protected void onEnable() { |
|
|
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 ; |
|
|
return ; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
con = new Connection(); |
|
|
|
|
|
con.isBusy = false; |
|
|
try { |
|
|
try { |
|
|
this.connection = new Socket(this.host, this.port); |
|
|
|
|
|
|
|
|
con.socket = new Socket(this.host, this.port); |
|
|
} catch (IOException e) { |
|
|
} catch (IOException e) { |
|
|
throw new RuntimeException(e); |
|
|
throw new RuntimeException(e); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
this.writer = new DataOutputStream(this.connection.getOutputStream()); |
|
|
|
|
|
|
|
|
con.writer = new DataOutputStream(con.socket.getOutputStream()); |
|
|
} catch (IOException e) { |
|
|
} catch (IOException e) { |
|
|
throw new RuntimeException(e); |
|
|
throw new RuntimeException(e); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
this.reader = this.connection.getInputStream(); |
|
|
|
|
|
|
|
|
con.reader = con.socket.getInputStream(); |
|
|
} catch (IOException e) { |
|
|
} catch (IOException e) { |
|
|
throw new RuntimeException(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); |
|
|
LOG.info("[Actuator {}({})] {} enable -- OK", this.key, this.type, this.name); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
protected void onDisable() { |
|
|
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 ; |
|
|
return ; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
try { |
|
|
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) { |
|
|
} catch (IOException e) { |
|
|
throw new RuntimeException(e); |
|
|
throw new RuntimeException(e); |
|
|
} |
|
|
} |
|
@ -103,12 +120,11 @@ public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implement |
|
|
cmd[3] = 0x00; // address low |
|
|
cmd[3] = 0x00; // address low |
|
|
cmd[4] = (byte)(temperature >> 8); // value high |
|
|
cmd[4] = (byte)(temperature >> 8); // value high |
|
|
cmd[5] = (byte)(temperature & 0xFF); // value low |
|
|
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); |
|
|
LOG.info("[Actuator {}({})] {} set temperature : {}", this.key, this.type, this.name, temperature); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// get temperature |
|
|
|
|
|
|
|
|
@Override |
|
|
public Integer getTemperature() { |
|
|
public Integer getTemperature() { |
|
|
byte[] cmd = new byte[8]; |
|
|
byte[] cmd = new byte[8]; |
|
|
cmd[0] = (byte)(this.slaveId & 0xFF); // slave id |
|
|
cmd[0] = (byte)(this.slaveId & 0xFF); // slave id |
|
@ -117,71 +133,99 @@ public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implement |
|
|
cmd[3] = 0x10; // address low |
|
|
cmd[3] = 0x10; // address low |
|
|
cmd[4] = 0x00; // length high |
|
|
cmd[4] = 0x00; // length high |
|
|
cmd[5] = 0x01; // length low |
|
|
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); |
|
|
LOG.info("[Actuator {}({})] {} get temperature : {}", this.key, this.type, this.name, temperature); |
|
|
return 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<Integer> 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<Integer> response = this.readCmdResponse(con); |
|
|
|
|
|
con.isBusy = false; |
|
|
|
|
|
synchronized ( con ) { |
|
|
|
|
|
con.notify(); |
|
|
|
|
|
} |
|
|
|
|
|
return response; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// write command |
|
|
// 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 size = cmd.length; |
|
|
var crc = this.calculateCRC(cmd, size - 2); |
|
|
var crc = this.calculateCRC(cmd, size - 2); |
|
|
cmd[size-2] = (byte)(crc & 0xFF); |
|
|
cmd[size-2] = (byte)(crc & 0xFF); |
|
|
cmd[size-1] = (byte)(crc >> 8); |
|
|
cmd[size-1] = (byte)(crc >> 8); |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
this.writer.write(cmd); |
|
|
|
|
|
this.writer.flush(); |
|
|
|
|
|
|
|
|
con.writer.write(cmd); |
|
|
|
|
|
con.writer.flush(); |
|
|
} catch (IOException e) { |
|
|
} catch (IOException e) { |
|
|
throw new RuntimeException(e); |
|
|
throw new RuntimeException(e); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// read command response |
|
|
|
|
|
private List<Integer> 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<Integer> readCmdResponse ( Connection con ) { |
|
|
try { |
|
|
try { |
|
|
List<Integer> result = new ArrayList<>(); |
|
|
List<Integer> 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; |
|
|
return result; |
|
|
} catch (IOException e) { |
|
|
} catch (IOException e) { |
|
|
throw new RuntimeException(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; |
|
|
|
|
|
} |
|
|
} |
|
|
} |