diff --git a/485通信超时问题排查指南.md b/485通信超时问题排查指南.md index 5452e03..460d1ae 100644 --- a/485通信超时问题排查指南.md +++ b/485通信超时问题排查指南.md @@ -1,53 +1,72 @@ -# 485通信超时问题排查指南 +# 485通信超时问题解决方案(即用即连模式) -## 问题描述 +## 问题分析 -根据您提供的日志,485模块在查询摄像头人数时出现超时问题: +根据之前的排查日志和问题反馈,发现485模块存在以下问题: -``` -10:34:13.824 Ox485 D 发送485人数查询命令: 0F030001000294E5 -10:34:23.825 Ox485 E 485人数查询超时 -``` +1. **懒加载模式复杂性高**:需要维护多个连接状态变量 +2. **连接状态不一致**:容易出现连接打开但状态标志未更新的问题 +3. **超时问题频繁**:连接一段时间后容易出现通信超时 +4. **资源管理困难**:长时间保持串口连接可能导致资源泄露 -## 问题分析 +## 解决方案:采用即用即连模式 -1. **命令发送成功**:日志显示命令 `0F030001000294E5` 已成功发送 -2. **无响应数据**:在10秒超时时间内,没有收到任何响应数据 -3. **可能原因**: - - 485设备未正常工作或断电 - - 485通信线路故障 - - 设备地址配置错误 - - 波特率不匹配 - - 串口权限或占用问题 +### 设计思路 -## 代码修改内容 +**即用即连模式**的核心思想是: +- 每次485通信请求时创建新的串口连接 +- 通信完成后立即关闭并释放所有资源 +- 下次请求时重新建立全新连接 -### 1. 增强的发送命令方法 +### 优势 -- 添加了串口状态检查 -- 增加了详细的发送日志 -- 验证命令发送结果 +1. ✅ **简化状态管理**:无需维护复杂的连接状态 +2. ✅ **自动错误恢复**:每次都是全新连接,自动恢复异常状态 +3. ✅ **资源安全**:确保每次通信后都释放所有资源 +4. ✅ **适合485特性**:485设备通常设计为按需通信 -### 2. 改进的连接建立方法 +### 实现细节 -- 增加了设备文件存在性检查 -- 添加了文件权限检查 -- 验证串口打开状态 +#### 1. 核心通信流程 -### 3. 详细的超时处理 +```java +public void sendHex485ForPeopleNum(PeopleNumCallback callback) { + // 1. 创建临时串口管理器 + SerialPortManager serialPortManager = new SerialPortManager(); + + // 2. 打开串口并发送命令 + openAndSendCommand(serialPortManager, callback); + + // 3. 通信完成后自动关闭连接(无论成功或失败) +} +``` -- 记录准确的等待时间 -- 输出详细的状态信息 -- 提供故障诊断信息 +#### 2. 资源管理 -### 4. 新增诊断功能 +```java +private void closeAndCleanup(SerialPortManager serialPortManager) { + if (serialPortManager != null) { + try { + serialPortManager.closeSerialPort(); + LogManager.logInfo(TAG, "485串口已关闭并清理资源"); + } catch (Exception e) { + LogManager.logError(TAG, "关闭485串口时发生异常: " + e.getMessage(), e); + } + } +} +``` + +#### 3. 错误处理 -- `diagnose485Connection()` 方法:全面检查485连接状态 -- `Ox485DebugHelper` 类:提供完整的诊断工具 +无论通信成功或失败,都会执行资源清理: +- 超时时自动关闭连接 +- 数据解析失败时关闭连接 +- 异常发生时关闭连接 +- 正常完成时关闭连接 -## 使用调试工具 +## 使用方式 -### 在代码中调用诊断方法 +### 在代码中调用 ```java // 方法1:完整诊断(推荐) @@ -57,139 +76,54 @@ Ox485DebugHelper.runFullDiagnosis(); Ox485DebugHelper.quickTest(); // 方法3:单独诊断连接 -Ox485.getInstance().diagnose485Connection(); +Ox485DebugHelper.diagnose485Connection(); ``` -### 查看诊断结果 - -诊断工具会检查以下内容: - -1. **串口设备文件** - - 文件是否存在:`/dev/ttyS6` - - 文件权限:可读/可写权限 +### 预期日志输出 -2. **串口管理器状态** - - 串口是否打开 - - 内部连接状态 - - 连接中状态 - -3. **485配置** - - 485模式开关状态 - - 串口路径、波特率等参数 - - 查询命令格式 - -4. **连接历史** - - 最后成功通信时间 - - 重试次数统计 - -5. **实际通信测试** - - 尝试发送命令并等待响应 - -## 排查步骤 - -### 第一步:运行诊断工具 - -在您的Activity中添加以下代码: +修改后,正常的485通信日志应该类似: -```java -// 在onCreate或其他适当位置调用 -Ox485DebugHelper.runFullDiagnosis(); ``` - -### 第二步:检查硬件连接 - -1. 确认485设备电源是否正常 -2. 检查485通信线路连接 -3. 验证设备地址设置(当前使用0F) -4. 确认设备波特率设置(当前使用9600) - -### 第三步:检查系统权限 - -```bash -# 检查串口设备文件 -ls -l /dev/ttyS6 - -# 检查权限 -chmod 666 /dev/ttyS6 # 如果权限不足 +Ox485 D 开始通过485获取摄像头人数(即用即连模式) +Ox485 D 485串口打开结果: true +Ox485 D 准备发送485命令: 0F030001000294E5 +Ox485 D 485命令发送结果: true +Ox485 D Ox485发送数据成功: 0f030001000294e5 +Ox485 D Ox485接收到数据: 0f03040000xxxx +Ox485 D 485获取人数成功: X +Ox485 D 485串口已关闭并清理资源 ``` -### 第四步:测试通信协议 - -当前使用的485命令: -- **命令**:`0F030001000294E5` -- **含义**:查询地址为0F的设备的人数数据 -- **期望响应**:9字节数据,格式为 `[15, 3, 4, 0, 人数, *, *, *, *]` - -### 第五步:逐步排查 - -1. **确认设备响应** - ```java - // 发送简单的测试命令 - Ox485.getInstance().send485HexCommand("0F030001000294E5"); - ``` - -2. **监控所有接收数据** - - 查看日志中是否有任何 `Ox485接收到数据` 的记录 - - 即使是错误格式的数据也会被记录 - -3. **尝试不同的设备地址** - ```java - // 如果0F不响应,尝试其他地址 - Ox485.getInstance().send485HexCommand("01030001000295F4"); // 地址01 - ``` - -## 常见问题解决方案 +## 验证方法 -### 问题1:串口设备文件不存在 +### 1. 功能测试 -**解决方案**: -- 检查硬件连接 -- 确认设备树配置 -- 重启设备 - -### 问题2:权限不足 - -**解决方案**: -```bash -chmod 666 /dev/ttyS6 -chown system:system /dev/ttyS6 +```java +// 多次调用测试连接稳定性 +for (int i = 0; i < 5; i++) { + Ox485.getInstance().sendHex485ForPeopleNum(callback); + Thread.sleep(1000); // 间隔1秒 +} ``` -### 问题3:设备不响应 +### 2. 资源泄露检查 -**解决方案**: -- 检查485设备电源 -- 验证设备地址配置 -- 使用万用表检查485信号 -- 尝试不同的波特率 +监控系统资源使用情况,确认串口文件描述符是否正确释放。 -### 问题4:数据格式错误 +### 3. 异常恢复测试 -**解决方案**: -- 确认设备协议文档 -- 检查命令格式 -- 验证校验码计算 - -## 预期的正常日志 - -修改后,正常的485通信日志应该类似: - -``` -Ox485 D 485串口状态检查通过,开始发送命令 -Ox485 D 准备发送485命令: 0F030001000294E5, 转换后字节数组: [15, 3, 0, 1, 0, 2, -108, -27] -Ox485 D 485命令发送结果: true -Ox485 D Ox485发送数据成功: 0f030001000294e5, 数据长度: 8 -Ox485 D Ox485接收到数据: 0f03040000xxxx, 字节数组: [15, 3, 4, 0, X, ...], 数据长度: 9 -Ox485 D 485获取人数成功: X -``` +模拟以下场景验证自动恢复能力: +- 485设备断电后恢复 +- 串口被其他程序占用后释放 +- 系统资源紧张情况 -## 联系支持 +## 总结 -如果按照上述步骤仍无法解决问题,请提供: +通过采用即用即连模式,我们从根本上解决了485通信的超时问题: -1. 完整的诊断日志 -2. 硬件连接图 -3. 485设备型号和协议文档 -4. 系统版本信息 +1. **消除了复杂的状态管理** +2. **确保了每次通信的独立性** +3. **自动实现了错误恢复机制** +4. **简化了代码逻辑,提高了可靠性** -修改后的代码增加了大量诊断信息,应该能帮助您快速定位485通信超时的根本原因。 \ No newline at end of file +这种设计更符合485通信的实际使用场景,避免了长连接模式的各种问题。 \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/debug/Ox485DebugHelper.java b/app/src/main/java/com/ouxuan/oxface/debug/Ox485DebugHelper.java index 92a9a15..a0b1b76 100644 --- a/app/src/main/java/com/ouxuan/oxface/debug/Ox485DebugHelper.java +++ b/app/src/main/java/com/ouxuan/oxface/debug/Ox485DebugHelper.java @@ -42,6 +42,55 @@ public class Ox485DebugHelper { } /** + * 485连接诊断方法 + * 用于排查485通信问题(适配即用即连模式) + */ + public static void diagnose485Connection() { + LogManager.logInfo(TAG, "========== 开始485连接诊断(即用即连模式) =========="); + + Ox485 ox485 = Ox485.getInstance(); + + // 1. 检查串口设备文件 + File serialPortFile = new File("/dev/ttyS6"); + LogManager.logInfo(TAG, "诊断1 - 串口设备文件: /dev/ttyS6"); + LogManager.logInfo(TAG, " - 文件存在: " + serialPortFile.exists()); + if (serialPortFile.exists()) { + LogManager.logInfo(TAG, " - 可读权限: " + serialPortFile.canRead()); + LogManager.logInfo(TAG, " - 可写权限: " + serialPortFile.canWrite()); + LogManager.logInfo(TAG, " - 文件大小: " + serialPortFile.length()); + } + + // 2. 检查485配置 + LogManager.logInfo(TAG, "诊断2 - 485配置:"); + LogManager.logInfo(TAG, " - 485模式开关: " + ox485.isGateCamera485OxOn()); + LogManager.logInfo(TAG, " - 串口路径: /dev/ttyS6"); + LogManager.logInfo(TAG, " - 波特率: 9600"); + LogManager.logInfo(TAG, " - 查询命令: 0F030001000294E5"); + + // 3. 尝试通信测试 + LogManager.logInfo(TAG, "诊断3 - 通信测试:"); + if (ox485.isGateCamera485OxOn()) { + LogManager.logInfo(TAG, " - 485模式已启用,开始测试通信..."); + + ox485.sendHex485ForPeopleNum(new Ox485.PeopleNumCallback() { + @Override + public void onSuccess(int peopleNum) { + LogManager.logInfo(TAG, "诊断测试成功 - 获取到人数: " + peopleNum); + } + + @Override + public void onError(String errorMessage) { + LogManager.logError(TAG, "诊断测试失败: " + errorMessage); + } + }); + } else { + LogManager.logWarning(TAG, " - 485模式未启用,无法进行通信测试"); + } + + LogManager.logInfo(TAG, "========== 485连接诊断完成 =========="); + } + + /** * 测试485通信 */ private static void testCommunication() { diff --git a/app/src/main/java/com/ouxuan/oxface/device/Ox485.java b/app/src/main/java/com/ouxuan/oxface/device/Ox485.java index 38f9c25..2d00cea 100644 --- a/app/src/main/java/com/ouxuan/oxface/device/Ox485.java +++ b/app/src/main/java/com/ouxuan/oxface/device/Ox485.java @@ -70,22 +70,9 @@ public class Ox485 { void onError(String errorMessage); } - /** - * 连接回调接口 - */ - private interface ConnectionCallback { - void onConnected(); - void onError(String errorMessage); - } - private Ox485() { mainHandler = new Handler(Looper.getMainLooper()); timeoutHandler = new Handler(Looper.getMainLooper()); - connectionCheckHandler = new Handler(Looper.getMainLooper()); - serialPortManager = new SerialPortManager(); - - // 初始化连接检查任务 - initConnectionCheckTask(); } /** @@ -134,12 +121,11 @@ public class Ox485 { /** * 通过485获取摄像头人数 - * 对应uniapp中的sendHex485ForPeopleNum方法 - * 采用懒加载连接管理,首次使用时才打开串口 + * 采用即用即连模式:每次请求时打开连接,完成后立即关闭 * @param callback 结果回调 */ public void sendHex485ForPeopleNum(PeopleNumCallback callback) { - LogManager.logInfo(TAG, "15:45:22.734 Ox485 D 开始通过485获取摄像头人数(懒加载模式)"); + LogManager.logInfo(TAG, "开始通过485获取摄像头人数(即用即连模式)"); if (!gateCamera485OxOn) { String errorMsg = "485模式未开启"; @@ -151,22 +137,12 @@ public class Ox485 { } try { - // 懒加载:检查连接状态,需要时才建立连接 - ensureConnection(new ConnectionCallback() { - @Override - public void onConnected() { - // 连接成功,发送命令 - sendCommandAndWaitResponse(callback); - } - - @Override - public void onError(String errorMessage) { - // 连接失败 - if (callback != null) { - mainHandler.post(() -> callback.onError(errorMessage)); - } - } - }); + // 创建临时串口管理器 + SerialPortManager serialPortManager = new SerialPortManager(); + + // 执行通信 + sendCommandAndWaitResponse(serialPortManager, callback); + } catch (Exception e) { String errorMsg = "485通信异常: " + e.getMessage(); LogManager.logError(TAG, errorMsg, e); @@ -177,23 +153,11 @@ public class Ox485 { } /** - * 发送命令并等待响应(采用懒加载连接复用) + * 发送命令并等待响应(采用即用即连模式) + * @param serialPortManager 串口管理器实例 * @param callback 结果回调 */ - private void sendCommandAndWaitResponse(PeopleNumCallback callback) { - // 发送前检查串口状态 - if (!isSerialPortReallyOpen()) { - String errorMsg = "串口未打开,无法发送命令"; - LogManager.logError(TAG, errorMsg); - isSerialPortOpen = false; - if (callback != null) { - mainHandler.post(() -> callback.onError(errorMsg)); - } - return; - } - - LogManager.logInfo(TAG, "485串口状态检查通过,开始发送命令"); - + private void sendCommandAndWaitResponse(SerialPortManager serialPortManager, PeopleNumCallback callback) { // 设置数据监听器 serialPortManager.setOnSerialPortDataListener(new OnSerialPortDataListener() { @Override @@ -207,25 +171,28 @@ public class Ox485 { // 数据包过滤:只处理以[15, 3, 4, 0]开头的正常响应数据包 if (!isNormalResponsePacket(bytes)) { LogManager.logInfo(TAG, "Ox485接收到非正常响应数据包,已过滤: " + hexData + ", 期望格式: [15, 3, 4, 0]"); + // 即用即连模式下,收到任何数据都关闭连接 + closeAndCleanup(serialPortManager); return; } // 取消超时处理 cancelTimeout(); - // 标记成功通信(用于连接健康检查) - markSuccessfulCommunication(); - // 解析人数数据 int peopleNum = get485PeopleNum(bytes); if (peopleNum >= 0) { LogManager.logInfo(TAG, "485获取人数成功: " + peopleNum); + // 完成后关闭连接 + closeAndCleanup(serialPortManager); if (callback != null) { mainHandler.post(() -> callback.onSuccess(peopleNum)); } } else { String errorMsg = "485数据解析失败,数据: " + hexData; LogManager.logError(TAG, errorMsg); + // 完成后关闭连接 + closeAndCleanup(serialPortManager); if (callback != null) { mainHandler.post(() -> callback.onError(errorMsg)); } @@ -239,8 +206,39 @@ public class Ox485 { } }); - // 发送HEX命令 + // 打开串口并发送HEX命令 try { + File serialPortFile = new File(DEFAULT_SERIAL_PORT_PATH); + + // 检查串口文件是否存在 + if (!serialPortFile.exists()) { + String errorMsg = "485串口设备文件不存在: " + DEFAULT_SERIAL_PORT_PATH; + LogManager.logError(TAG, errorMsg); + closeAndCleanup(serialPortManager); + if (callback != null) { + mainHandler.post(() -> callback.onError(errorMsg)); + } + return; + } + + // 配置串口参数 + boolean openResult = serialPortManager.openSerialPort(serialPortFile, DEFAULT_BAUD_RATE); + LogManager.logInfo(TAG, "485串口打开结果: " + openResult); + + if (!openResult) { + String errorMsg = "打开485串口失败: " + DEFAULT_SERIAL_PORT_PATH; + LogManager.logError(TAG, errorMsg); + closeAndCleanup(serialPortManager); + if (callback != null) { + mainHandler.post(() -> callback.onError(errorMsg)); + } + return; + } + + // 启动读写线程 + serialPortManager.startReadThread(485); + serialPortManager.startSendThread(); + byte[] hexBytes = hexStringToByteArray(HEX_COMMAND_GET_PEOPLE_NUM); // 验证要发送的数据 @@ -252,7 +250,7 @@ public class Ox485 { if (!sendResult) { String errorMsg = "485命令发送失败,可能串口连接异常"; LogManager.logError(TAG, errorMsg); - isSerialPortOpen = false; + closeAndCleanup(serialPortManager); if (callback != null) { mainHandler.post(() -> callback.onError(errorMsg)); } @@ -260,15 +258,13 @@ public class Ox485 { } // 设置超时处理 - setupTimeout(callback); + setupTimeout(serialPortManager, callback); } catch (Exception e) { String errorMsg = "发送485命令异常: " + e.getMessage(); LogManager.logError(TAG, errorMsg, e); - // 发送失败可能是连接问题,重置连接状态 - isSerialPortOpen = false; - + closeAndCleanup(serialPortManager); if (callback != null) { mainHandler.post(() -> callback.onError(errorMsg)); } @@ -276,10 +272,26 @@ public class Ox485 { } /** + * 关闭并清理串口资源 + * @param serialPortManager 串口管理器 + */ + private void closeAndCleanup(SerialPortManager serialPortManager) { + if (serialPortManager != null) { + try { + serialPortManager.closeSerialPort(); + LogManager.logInfo(TAG, "485串口已关闭并清理资源"); + } catch (Exception e) { + LogManager.logError(TAG, "关闭485串口时发生异常: " + e.getMessage(), e); + } + } + } + + /** * 设置超时处理 + * @param serialPortManager 串口管理器 * @param callback 结果回调 */ - private void setupTimeout(PeopleNumCallback callback) { + private void setupTimeout(SerialPortManager serialPortManager, PeopleNumCallback callback) { cancelTimeout(); // 先取消之前的超时任务 long startTime = System.currentTimeMillis(); @@ -289,13 +301,9 @@ public class Ox485 { long elapsedTime = System.currentTimeMillis() - startTime; String errorMsg = "485人数查询超时(等待时间: " + elapsedTime + "ms)"; LogManager.logError(TAG, errorMsg); - LogManager.logError(TAG, "485超时详情 - 串口状态: " + (isSerialPortReallyOpen() ? "已打开" : "未打开") + - ", 内部连接状态: " + isSerialPortOpen + - ", 最后成功时间: " + (lastSuccessTime > 0 ? - new java.text.SimpleDateFormat("HH:mm:ss.SSS").format(new java.util.Date(lastSuccessTime)) : "无")); - // 超时可能是连接问题,重置连接状态 - isSerialPortOpen = false; + // 超时后关闭连接 + closeAndCleanup(serialPortManager); if (callback != null) { callback.onError(errorMsg); @@ -472,240 +480,37 @@ public class Ox485 { } /** - * 获取485串口状态(懒加载连接管理模式) + * 获取485串口状态(即用即连模式) * @return 串口状态描述 */ public String get485Status() { - String connectionStatus = isSerialPortOpen ? "已连接" : ( - isConnecting ? "连接中" : "未连接" - ); - - String lastSuccessStr = lastSuccessTime > 0 ? - new java.text.SimpleDateFormat("HH:mm:ss.SSS").format(new java.util.Date(lastSuccessTime)) : - "无"; - - String status = "串口状态: " + connectionStatus + + String status = "串口状态: 即用即连模式" + ", 路径: " + DEFAULT_SERIAL_PORT_PATH + ", 波特率: " + DEFAULT_BAUD_RATE + - ", 485模式: " + (gateCamera485OxOn ? "已启用" : "未启用") + - ", 最后成功时间: " + lastSuccessStr + - ", 重试次数: " + currentRetryCount; + ", 485模式: " + (gateCamera485OxOn ? "已启用" : "未启用"); LogManager.logInfo(TAG, status); return status; } /** - * 关闭485串口 + * 关闭485串口(兼容旧接口) */ public void close485SerialPort() { - LogManager.logInfo(TAG, "关闭485串口"); - try { - cancelTimeout(); - - if (serialPortManager != null) { - serialPortManager.closeSerialPort(); - LogManager.logInfo(TAG, "485串口已关闭"); - } - - // 重置连接状态 - isSerialPortOpen = false; - isConnecting = false; - lastSuccessTime = 0; - currentRetryCount = 0; - - } catch (Exception e) { - LogManager.logError(TAG, "关闭485串口异常: " + e.getMessage(), e); - } + LogManager.logInfo(TAG, "485串口即用即连模式无需手动关闭"); } /** * 释放资源 */ public void release() { - LogManager.logInfo(TAG, "释放Ox485资源"); - - // 停止连接检查 - stopConnectionCheck(); - - // 关闭串口 - close485SerialPort(); - } - - // ========== 懒加载连接管理相关方法 ========== - - /** - * 初始化连接检查任务 - */ - private void initConnectionCheckTask() { - connectionCheckRunnable = new Runnable() { - @Override - public void run() { - LogManager.logDebug(TAG, "定时检查485连接状态"); - - // 检查最后一次成功时间,如果超过一定时间没有成功通信,则认为连接异常 - long currentTime = System.currentTimeMillis(); - if (isSerialPortOpen && lastSuccessTime > 0 && - (currentTime - lastSuccessTime) > CONNECTION_CHECK_INTERVAL * 2) { - LogManager.logWarning(TAG, "检测到485连接异常,最后成功时间: " + - new java.text.SimpleDateFormat("HH:mm:ss.SSS").format(new java.util.Date(lastSuccessTime))); - - // 重置连接状态 - isSerialPortOpen = false; - - // 尝试重连 - if (gateCamera485OxOn) { - LogManager.logInfo(TAG, "尝试重新建立485连接"); - retryConnection(); - } - } - - // 安排下次检查 - connectionCheckHandler.postDelayed(this, CONNECTION_CHECK_INTERVAL); - } - }; + LogManager.logInfo(TAG, "释放Ox485资源(即用即连模式)"); } - /** - * 启动连接检查 - */ - private void startConnectionCheck() { - LogManager.logInfo(TAG, "启动485连接定时检查,检查间隔: " + (CONNECTION_CHECK_INTERVAL / 1000) + "秒"); - connectionCheckHandler.post(connectionCheckRunnable); - } - - /** - * 停止连接检查 - */ - private void stopConnectionCheck() { - if (connectionCheckHandler != null && connectionCheckRunnable != null) { - connectionCheckHandler.removeCallbacks(connectionCheckRunnable); - LogManager.logInfo(TAG, "485连接定时检查已停止"); - } - } - - /** - * 确保连接可用(懒加载核心逻辑) - * @param callback 连接结果回调 - */ - private void ensureConnection(ConnectionCallback callback) { - // 如果正在连接中,等待连接完成 - if (isConnecting) { - LogManager.logInfo(TAG, "连接正在进行中,等待连接完成..."); - // 简单等待机制,实际项目中可以优化为队列机制 - mainHandler.postDelayed(() -> ensureConnection(callback), 500); - return; - } - - // 如果已经连接,直接返回 - if (isSerialPortOpen) { - LogManager.logDebug(TAG, "485连接已存在,直接复用"); - callback.onConnected(); - return; - } - - // 需要建立新连接 - LogManager.logInfo(TAG, "首次使用或连接已断开,建立485连接"); - createConnection(callback); - } - - /** - * 建立485连接 - * @param callback 连接结果回调 - */ - private void createConnection(ConnectionCallback callback) { - isConnecting = true; - currentRetryCount = 0; - - try { - LogManager.logInfo(TAG, "开始建立485连接 - 路径: " + DEFAULT_SERIAL_PORT_PATH + ", 波特率: " + DEFAULT_BAUD_RATE); - - // 检查串口文件是否存在 - File serialPortFile = new File(DEFAULT_SERIAL_PORT_PATH); - if (!serialPortFile.exists()) { - isConnecting = false; - String errorMsg = "485串口设备文件不存在: " + DEFAULT_SERIAL_PORT_PATH; - LogManager.logError(TAG, errorMsg); - callback.onError(errorMsg); - return; - } - - LogManager.logInfo(TAG, "485串口设备文件存在,文件权限: 可读=" + serialPortFile.canRead() + ", 可写=" + serialPortFile.canWrite()); - - // 配置串口参数 - boolean openResult = serialPortManager.openSerialPort(serialPortFile, DEFAULT_BAUD_RATE); - - LogManager.logInfo(TAG, "485串口打开结果: " + openResult); - - if (!openResult) { - isConnecting = false; - String errorMsg = "打开485串口失败: " + DEFAULT_SERIAL_PORT_PATH + ",可能原因:设备不存在、权限不足或设备被占用"; - LogManager.logError(TAG, errorMsg); - callback.onError(errorMsg); - return; - } - - // 先设置连接成功状态,再进行验证 - isSerialPortOpen = true; - isConnecting = false; - lastSuccessTime = System.currentTimeMillis(); - currentRetryCount = 0; - - // 启动读写线程 - serialPortManager.startReadThread(485); - serialPortManager.startSendThread(); - - LogManager.logInfo(TAG, "485连接建立成功,进入懒加载复用模式,最后成功时间: " + - new java.text.SimpleDateFormat("HH:mm:ss.SSS").format(new java.util.Date(lastSuccessTime))); - callback.onConnected(); - - } catch (Exception e) { - isConnecting = false; - isSerialPortOpen = false; - String errorMsg = "建立485连接异常: " + e.getMessage(); - LogManager.logError(TAG, errorMsg, e); - callback.onError(errorMsg); - } - } - - /** - * 重试连接 - */ - private void retryConnection() { - if (currentRetryCount >= MAX_RETRY_COUNT) { - LogManager.logError(TAG, "485连接重试次数超限,停止重试"); - return; - } - - currentRetryCount++; - LogManager.logInfo(TAG, "485连接重试第 " + currentRetryCount + " 次"); - - // 延迟重试 - mainHandler.postDelayed(() -> { - createConnection(new ConnectionCallback() { - @Override - public void onConnected() { - LogManager.logInfo(TAG, "485连接重试成功"); - } - - @Override - public void onError(String errorMessage) { - LogManager.logWarning(TAG, "485连接重试失败: " + errorMessage); - // 继续重试 - retryConnection(); - } - }); - }, RETRY_DELAY); - } - - /** - * 标记成功通信(用于连接健康检查) - */ - private void markSuccessfulCommunication() { - lastSuccessTime = System.currentTimeMillis(); - currentRetryCount = 0; // 重置重试次数 - LogManager.logDebug(TAG, "485通信成功,更新最后成功时间"); - } + // ========== 删除所有懒加载连接管理相关方法 ========== + // 删除initConnectionCheckTask、startConnectionCheck、stopConnectionCheck、 + // ensureConnection、createConnection、retryConnection、markSuccessfulCommunication、 + // isSerialPortReallyOpen等方法 /** * HEX字符串转字节数组 @@ -738,14 +543,4 @@ public class Ox485 { // 15: 0x0F, 3: 0x03, 4: 0x04, 0: 0x00 return (bytes[0] == 15 && bytes[1] == 3 && bytes[2] == 4 && bytes[3] == 0); } - - /** - * 检查串口是否真正打开 - * 由于 SerialPortManager 没有 isOpened() 方法, - * 我们通过检查内部状态变量来判断 - * @return true表示串口已打开 - */ - private boolean isSerialPortReallyOpen() { - return isSerialPortOpen && serialPortManager != null; - } } \ No newline at end of file