From 02026f0fd1dbc51cf704702c074d263fa5c676db Mon Sep 17 00:00:00 2001 From: sige Date: Tue, 19 Mar 2024 15:07:39 +0800 Subject: [PATCH] ~~ --- .../diframe/actuator/DiActHeater.java | 12 ++ .../impl/DiActHeaterTokyGteModbusRtuOverTcp.java | 187 +++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/DiActHeater.java create mode 100644 src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/impl/DiActHeaterTokyGteModbusRtuOverTcp.java diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/DiActHeater.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/DiActHeater.java new file mode 100644 index 0000000..f7b6942 --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/DiActHeater.java @@ -0,0 +1,12 @@ +package com.my.graphiteDigesterBg.diframe.actuator; +public interface DiActHeater { + // set temperature + void setTemperature( Integer temperature ); + + // get temperature + Integer getTemperature(); + + void start(); + + void stop(); +} 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 new file mode 100644 index 0000000..b6b8b4c --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/impl/DiActHeaterTokyGteModbusRtuOverTcp.java @@ -0,0 +1,187 @@ +package com.my.graphiteDigesterBg.diframe.actuator.impl; +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.List; + +public class DiActHeaterTokyGteModbusRtuOverTcp extends DiActuatorBase implements DiActHeater { + // host + private String host; + // port + private Integer port; + // slave id + private Integer slaveId; + // heater key + private String ioKey; + // connection + private Socket connection; + // writer + private DataOutputStream writer; + // reader + private InputStream reader; + + @Override + public void setEnable( Boolean enable ) { + if ( enable ) { + this.onEnable(); + } else { + this.onDisable(); + } + } + + @Override + protected void onEnable() { + if ( null != this.connection ) { + return ; + } + + try { + this.connection = new Socket(this.host, this.port); + } catch (IOException e) { + throw new RuntimeException(e); + } + + try { + this.writer = new DataOutputStream(this.connection.getOutputStream()); + } catch (IOException e) { + throw new RuntimeException(e); + } + + try { + this.reader = this.connection.getInputStream(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + LOG.info("[Actuator {}({})] {} enable -- OK", this.key, this.type, this.name); + } + + @Override + protected void onDisable() { + if ( null == this.connection ) { + return ; + } + + try { + this.connection.close(); + this.connection = null; + } catch (IOException e) { + throw new RuntimeException(e); + } + try { + this.writer.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + LOG.info("[Actuator {}({})] {} disable -- OK", this.key, this.type, this.name); + } + + @Override + public void start() { + this.device.getIO().setValue(this.ioKey, 1); + LOG.info("[Actuator {}({})] {} heating : start", this.key, this.type, this.name); + } + + @Override + public void stop() { + this.device.getIO().setValue(this.ioKey, 0); + LOG.info("[Actuator {}({})] {} heating : stop", this.key, this.type, this.name); + this.setTemperature(10); + } + + @Override + public void setTemperature(Integer temperature) { + byte[] cmd = new byte[8]; + cmd[0] = (byte)(this.slaveId & 0xFF); // slave id + cmd[1] = 0x06; // function code + cmd[2] = 0x20; // address high + cmd[3] = 0x00; // address low + cmd[4] = (byte)(temperature >> 8); // value high + cmd[5] = (byte)(temperature & 0xFF); // value low + this.writeCmd(cmd); + this.readCmdResponse(); + LOG.info("[Actuator {}({})] {} set temperature : {}", this.key, this.type, this.name, temperature); + } + + // get temperature + public Integer getTemperature() { + byte[] cmd = new byte[8]; + cmd[0] = (byte)(this.slaveId & 0xFF); // slave id + cmd[1] = 0x03; // function code + cmd[2] = 0x20; // address high + 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); + 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的初始值 + + 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; + } + + // write command + private void writeCmd( byte[] cmd ) { + if ( null == this.connection ) { + throw new RuntimeException("加热器"+this.key+"未启用"); + } + + 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(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // read command response + private List readCmdResponse () { + if ( null == this.connection ) { + throw new RuntimeException("加热器"+this.key+"未启用"); + } + + try { + List result = new ArrayList<>(); + while ( 0 < this.reader.available() ) { + result.add(this.reader.read()); + } + return result; + } catch (IOException e) { + throw new RuntimeException(e); + } + } +}