feat(Property): 优化定时任务执行逻辑并添加时间限制

This commit is contained in:
2025-09-08 17:48:10 +08:00
parent 71c82fa345
commit 6a2898e0d7
4 changed files with 165 additions and 96 deletions

View File

@@ -9,6 +9,8 @@ import java.io.IOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import static com.ghgande.j2mod.modbus.Modbus.WRITE_SINGLE_REGISTER;
@@ -24,9 +26,8 @@ public class LightingUtil {
private static final int MODBUS_PORT = 502;
// 功能码03读保持寄存器
private static final byte FUNCTION_CODE = 0x03;
// 采集寄存器范围(协议地址)
private static final int START_ADDRESS = 42; // 40043 - 40001 = 42
private static final int REGISTER_COUNT = 4; // 40046 - 40043 + 1 = 4
// Modbus协议一次最多读取的寄存器数量
private static final int MAX_REGISTERS_PER_REQUEST = 63;
private Socket socket;
private DataInputStream input;
@@ -70,78 +71,6 @@ public class LightingUtil {
return header;
}
/**
* 读取40043-40046寄存器数据
*
* @return 包含4个寄存器值的int数组
*/
public int[] readRegisters() throws IOException {
// 发送读取请求
sendRequest();
// 接收并解析响应
return parseResponse();
}
/**
* 构造并发送Modbus TCP请求帧
*/
private void sendRequest() throws IOException {
// 事务ID递增
int currentTransactionId = transactionId++;
// 创建请求帧12字节
ByteBuffer buffer = ByteBuffer.allocate(12)
.order(ByteOrder.BIG_ENDIAN);
// Header7字节
buffer.putShort((short) currentTransactionId); // 事务ID
buffer.putShort((short) 0); // 协议ID0=Modbus
buffer.putShort((short) 6); // 长度(后续字节数)
buffer.put((byte) 1); // 单元ID
// PDU协议数据单元
buffer.put(FUNCTION_CODE); // 功能码
buffer.putShort((short) START_ADDRESS); // 起始地址
buffer.putShort((short) REGISTER_COUNT); // 寄存器数量
output.write(buffer.array());
output.flush();
}
/**
* 解析Modbus TCP响应
*/
private int[] parseResponse() throws IOException {
// 读取头7字节
byte[] header = initParse();
// 读取PDU协议数据单元
int pduLength = ByteBuffer.wrap(header, 4, 2)
.getShort() & 0xFFFF - 1; // 减去单元ID长度
byte[] pdu = new byte[pduLength];
input.readFully(pdu);
// 检查异常响应功能码高位为1
if ((pdu[0] & 0xFF) == (FUNCTION_CODE | 0x80)) {
throw new IOException("Modbus异常响应错误码: " + (pdu[1] & 0xFF));
}
// 验证功能码和字节数
if (pdu[0] != FUNCTION_CODE || pdu[1] != REGISTER_COUNT * 2) {
throw new IOException("无效响应格式");
}
// 提取寄存器数据每个寄存器2字节
int[] values = new int[REGISTER_COUNT];
for (int i = 0; i < REGISTER_COUNT; i++) {
int offset = 2 + i * 2;
values[i] = ByteBuffer.wrap(pdu, offset, 2)
.order(ByteOrder.BIG_ENDIAN).getShort() & 0xFFFF;
}
return values;
}
/**
* 写单个保持寄存器功能码06
*
@@ -214,5 +143,128 @@ public class LightingUtil {
return true;
}
/**
* 读取指定数量的开关状态
*
* @param startAddress 起始地址(协议地址)
* @param switchCount 开关数量
* @return 包含所有开关状态的int数组每个元素代表一个开关的状态
* @throws IOException 如果读取过程中发生IO错误
*/
public int[] readSwitchStatus(int startAddress, int switchCount) throws IOException {
// 如果开关数量超过单次请求限制,分批读取
if (switchCount > MAX_REGISTERS_PER_REQUEST) {
return readSwitchStatusBatch(startAddress, switchCount);
}
// 发送读取请求
sendCustomRequest(startAddress, switchCount);
// 接收并解析响应
return parseCustomResponse(switchCount);
}
/**
* 分批读取大量开关状态
*/
private int[] readSwitchStatusBatch(int startAddress, int totalSwitchCount) throws IOException {
List<Integer> allValues = new ArrayList<>();
int remaining = totalSwitchCount;
int currentAddress = startAddress;
while (remaining > 0) {
int batchSize = Math.min(remaining, MAX_REGISTERS_PER_REQUEST);
// 发送读取请求
sendCustomRequest(currentAddress, batchSize);
// 接收并解析响应
int[] batchValues = parseCustomResponse(batchSize);
// 添加到结果列表
for (int value : batchValues) {
allValues.add(value);
}
// 更新剩余数量和当前地址
remaining -= batchSize;
currentAddress += batchSize;
// 添加小延迟,避免请求过快
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("读取过程被中断", e);
}
}
// 转换为数组返回
int[] result = new int[allValues.size()];
for (int i = 0; i < allValues.size(); i++) {
result[i] = allValues.get(i);
}
return result;
}
/**
* 构造并发送自定义Modbus TCP请求帧
*/
private void sendCustomRequest(int startAddress, int registerCount) throws IOException {
// 事务ID递增
int currentTransactionId = transactionId++;
// 创建请求帧12字节
ByteBuffer buffer = ByteBuffer.allocate(12)
.order(ByteOrder.BIG_ENDIAN);
// Header7字节
buffer.putShort((short) currentTransactionId); // 事务ID
buffer.putShort((short) 0); // 协议ID0=Modbus
buffer.putShort((short) 6); // 长度(后续字节数)
buffer.put((byte) 1); // 单元ID
// PDU协议数据单元
buffer.put(FUNCTION_CODE); // 功能码
buffer.putShort((short) startAddress); // 起始地址
buffer.putShort((short) registerCount); // 寄存器数量
output.write(buffer.array());
output.flush();
}
/**
* 解析自定义Modbus TCP响应
*/
private int[] parseCustomResponse(int expectedRegisterCount) throws IOException {
// 读取头7字节
byte[] header = initParse();
// 读取PDU协议数据单元
int pduLength = ByteBuffer.wrap(header, 4, 2)
.getShort() & 0xFFFF - 1; // 减去单元ID长度
byte[] pdu = new byte[pduLength];
input.readFully(pdu);
// 检查异常响应功能码高位为1
if ((pdu[0] & 0xFF) == (FUNCTION_CODE | 0x80)) {
throw new IOException("Modbus异常响应错误码: " + (pdu[1] & 0xFF));
}
// 验证功能码和字节数
if (pdu[0] != FUNCTION_CODE || pdu[1] != expectedRegisterCount * 2) {
throw new IOException("无效响应格式");
}
// 提取寄存器数据每个寄存器2字节
int[] values = new int[expectedRegisterCount];
for (int i = 0; i < expectedRegisterCount; i++) {
int offset = 2 + i * 2;
values[i] = ByteBuffer.wrap(pdu, offset, 2)
.order(ByteOrder.BIG_ENDIAN).getShort() & 0xFFFF;
}
return values;
}
}