|
|
@ -18,11 +18,11 @@ import java.util.concurrent.TimeUnit; |
|
|
|
* Ox485 串口通信模块 |
|
|
|
* 基于kongqw/SerialPortLibrary实现485通信功能 |
|
|
|
* 主要用于获取摄像头人数等485设备通信 |
|
|
|
* 采用懒加载连接管理模式:首次使用时打开,保持连接状态,定时检查机制 |
|
|
|
* 采用即用即连模式:每次请求时打开连接,完成后立即关闭,确保通信可靠性 |
|
|
|
* |
|
|
|
* @author AI Assistant |
|
|
|
* @version 2.0 |
|
|
|
* @date 2024/09/15 |
|
|
|
* @version 3.0 - 即用即连模式 |
|
|
|
* @date 2024/09/22 |
|
|
|
*/ |
|
|
|
public class Ox485 { |
|
|
|
|
|
|
@ -35,8 +35,7 @@ public class Ox485 { |
|
|
|
private static final String HEX_COMMAND_GET_PEOPLE_NUM = "0F030001000294E5"; |
|
|
|
private static final long TIMEOUT_485_MILLIS = 10000; // 10秒超时 |
|
|
|
|
|
|
|
// 懒加载连接管理配置 |
|
|
|
private static final long CONNECTION_CHECK_INTERVAL = 30000; // 30秒检查一次连接状态 |
|
|
|
// 即用即连模式配置 |
|
|
|
private static final int MAX_RETRY_COUNT = 3; // 最大重试次数 |
|
|
|
private static final long RETRY_DELAY = 1000; // 重试延迟1秒 |
|
|
|
|
|
|
@ -44,19 +43,10 @@ public class Ox485 { |
|
|
|
private static volatile Ox485 instance; |
|
|
|
|
|
|
|
// 485通信相关 |
|
|
|
private SerialPortManager serialPortManager; |
|
|
|
private Handler mainHandler; |
|
|
|
private boolean gateCamera485OxOn = false; |
|
|
|
private Context context; |
|
|
|
|
|
|
|
// 懒加载连接管理相关 |
|
|
|
private boolean isSerialPortOpen = false; // 串口是否已打开 |
|
|
|
private boolean isConnecting = false; // 是否正在连接中 |
|
|
|
private Handler connectionCheckHandler; // 连接检查处理器 |
|
|
|
private Runnable connectionCheckRunnable; // 连接检查任务 |
|
|
|
private long lastSuccessTime = 0; // 最后一次成功通信时间 |
|
|
|
private int currentRetryCount = 0; // 当前重试次数 |
|
|
|
|
|
|
|
// 数据接收相关 |
|
|
|
private long lastRecvTime = 0; |
|
|
|
private Handler timeoutHandler; |
|
|
@ -96,10 +86,7 @@ public class Ox485 { |
|
|
|
*/ |
|
|
|
public void initialize(Context context) { |
|
|
|
this.context = context; |
|
|
|
LogManager.logInfo(TAG, "15:45:22.734 Ox485 D Ox485模块初始化完成,采用懒加载连接管理模式"); |
|
|
|
|
|
|
|
// 启动定时连接检查 |
|
|
|
startConnectionCheck(); |
|
|
|
LogManager.logInfo(TAG, "Ox485模块初始化完成,采用即用即连模式"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -108,7 +95,7 @@ public class Ox485 { |
|
|
|
*/ |
|
|
|
public void setGateCamera485OxOn(boolean enabled) { |
|
|
|
this.gateCamera485OxOn = enabled; |
|
|
|
LogManager.logInfo(TAG, "15:45:22.734 Ox485 D 设置485模式开关: " + enabled); |
|
|
|
LogManager.logInfo(TAG, "设置485模式开关: " + enabled); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -272,21 +259,6 @@ 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 结果回调 |
|
|
@ -351,7 +323,7 @@ public class Ox485 { |
|
|
|
|
|
|
|
// 提取第5个字节作为人数数据,使用位掩码确保为无符号整数 |
|
|
|
int peopleNum = arr[4] & 0xFF; |
|
|
|
LogManager.logInfo(TAG, "15:45:22.734 Ox485 D 解析485人数成功: " + peopleNum); |
|
|
|
LogManager.logInfo(TAG, "解析485人数成功: " + peopleNum); |
|
|
|
|
|
|
|
return peopleNum; |
|
|
|
} |
|
|
@ -384,7 +356,7 @@ public class Ox485 { |
|
|
|
* 检查是否需要打开485串口 |
|
|
|
*/ |
|
|
|
public void checkIsNeedOpen485() { |
|
|
|
LogManager.logInfo(TAG, "检查485串口状态(懒加载模式)"); |
|
|
|
LogManager.logInfo(TAG, "检查485串口状态(即用即连模式)"); |
|
|
|
String status = get485Status(); |
|
|
|
LogManager.logInfo(TAG, status); |
|
|
|
} |
|
|
@ -396,22 +368,71 @@ public class Ox485 { |
|
|
|
public void send485HexCommand(String hexCommand) { |
|
|
|
LogManager.logInfo(TAG, "发送485 HEX命令: " + hexCommand); |
|
|
|
try { |
|
|
|
if (!isSerialPortOpen) { |
|
|
|
LogManager.logWarning(TAG, "串口未打开,无法发送命令"); |
|
|
|
if (!gateCamera485OxOn) { |
|
|
|
LogManager.logWarning(TAG, "485模式未开启,无法发送命令"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 创建临时串口管理器发送命令 |
|
|
|
SerialPortManager serialPortManager = new SerialPortManager(); |
|
|
|
File serialPortFile = new File(DEFAULT_SERIAL_PORT_PATH); |
|
|
|
|
|
|
|
if (!serialPortFile.exists()) { |
|
|
|
LogManager.logWarning(TAG, "串口设备文件不存在: " + DEFAULT_SERIAL_PORT_PATH); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
boolean openResult = serialPortManager.openSerialPort(serialPortFile, DEFAULT_BAUD_RATE); |
|
|
|
if (!openResult) { |
|
|
|
LogManager.logWarning(TAG, "打开串口失败: " + DEFAULT_SERIAL_PORT_PATH); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
serialPortManager.startReadThread(485); |
|
|
|
serialPortManager.startSendThread(); |
|
|
|
|
|
|
|
byte[] hexBytes = hexStringToByteArray(hexCommand); |
|
|
|
serialPortManager.sendBytes(hexBytes); |
|
|
|
LogManager.logInfo(TAG, "485命令发送完成"); |
|
|
|
|
|
|
|
// 发送完成后关闭连接 |
|
|
|
closeAndCleanup(serialPortManager); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
LogManager.logError(TAG, "发送485命令异常: " + e.getMessage(), e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取485串口状态(即用即连模式) |
|
|
|
* @return 串口状态描述 |
|
|
|
*/ |
|
|
|
public String get485Status() { |
|
|
|
String status = "串口状态: 即用即连模式" + |
|
|
|
", 路径: " + DEFAULT_SERIAL_PORT_PATH + |
|
|
|
", 波特率: " + DEFAULT_BAUD_RATE + |
|
|
|
", 485模式: " + (gateCamera485OxOn ? "已启用" : "未启用"); |
|
|
|
|
|
|
|
LogManager.logInfo(TAG, status); |
|
|
|
return status; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 关闭485串口(兼容旧接口) |
|
|
|
*/ |
|
|
|
public void close485SerialPort() { |
|
|
|
LogManager.logInfo(TAG, "485串口即用即连模式无需手动关闭"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 释放资源 |
|
|
|
*/ |
|
|
|
public void release() { |
|
|
|
LogManager.logInfo(TAG, "释放Ox485资源(即用即连模式)"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 485连接诊断方法 |
|
|
|
* 用于排查485通信问题 |
|
|
|
*/ |
|
|
|
public void diagnose485Connection() { |
|
|
|
LogManager.logInfo(TAG, "开始485连接诊断"); |
|
|
@ -426,41 +447,18 @@ public class Ox485 { |
|
|
|
LogManager.logInfo(TAG, " - 文件大小: " + serialPortFile.length()); |
|
|
|
} |
|
|
|
|
|
|
|
// 2. 检查串口管理器状态 |
|
|
|
LogManager.logInfo(TAG, "诊断2 - 串口管理器状态:"); |
|
|
|
LogManager.logInfo(TAG, " - 串口是否打开: " + (isSerialPortReallyOpen() ? "已打开" : "未打开")); |
|
|
|
LogManager.logInfo(TAG, " - 内部连接状态: " + isSerialPortOpen); |
|
|
|
LogManager.logInfo(TAG, " - 是否连接中: " + isConnecting); |
|
|
|
|
|
|
|
// 3. 检查485模式开关 |
|
|
|
LogManager.logInfo(TAG, "诊断3 - 485配置:"); |
|
|
|
// 2. 检查485配置 |
|
|
|
LogManager.logInfo(TAG, "诊断2 - 485配置:"); |
|
|
|
LogManager.logInfo(TAG, " - 485模式开关: " + gateCamera485OxOn); |
|
|
|
LogManager.logInfo(TAG, " - 串口路径: " + DEFAULT_SERIAL_PORT_PATH); |
|
|
|
LogManager.logInfo(TAG, " - 波特率: " + DEFAULT_BAUD_RATE); |
|
|
|
LogManager.logInfo(TAG, " - 停止位: " + DEFAULT_STOP_BITS); |
|
|
|
LogManager.logInfo(TAG, " - 查询命令: " + HEX_COMMAND_GET_PEOPLE_NUM); |
|
|
|
|
|
|
|
// 4. 检查连接历史 |
|
|
|
LogManager.logInfo(TAG, "诊断4 - 连接历史:"); |
|
|
|
String lastSuccessStr = lastSuccessTime > 0 ? |
|
|
|
new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new java.util.Date(lastSuccessTime)) : |
|
|
|
"无"; |
|
|
|
LogManager.logInfo(TAG, " - 最后成功时间: " + lastSuccessStr); |
|
|
|
LogManager.logInfo(TAG, " - 当前重试次数: " + currentRetryCount); |
|
|
|
LogManager.logInfo(TAG, " - 最大重试次数: " + MAX_RETRY_COUNT); |
|
|
|
|
|
|
|
// 5. 尝试重新建立连接进行测试 |
|
|
|
LogManager.logInfo(TAG, "诊断5 - 连接测试:"); |
|
|
|
// 3. 尝试通信测试 |
|
|
|
LogManager.logInfo(TAG, "诊断3 - 通信测试:"); |
|
|
|
if (gateCamera485OxOn) { |
|
|
|
LogManager.logInfo(TAG, " - 485模式已启用,尝试测试连接..."); |
|
|
|
LogManager.logInfo(TAG, " - 485模式已启用,开始测试通信..."); |
|
|
|
|
|
|
|
// 强制关闭现有连接 |
|
|
|
if (isSerialPortOpen) { |
|
|
|
LogManager.logInfo(TAG, " - 关闭现有连接进行重新测试"); |
|
|
|
close485SerialPort(); |
|
|
|
} |
|
|
|
|
|
|
|
// 尝试重新连接并发送测试命令 |
|
|
|
sendHex485ForPeopleNum(new PeopleNumCallback() { |
|
|
|
@Override |
|
|
|
public void onSuccess(int peopleNum) { |
|
|
@ -473,45 +471,27 @@ public class Ox485 { |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
LogManager.logWarning(TAG, " - 485模式未启用,无法进行连接测试"); |
|
|
|
LogManager.logWarning(TAG, " - 485模式未启用,无法进行通信测试"); |
|
|
|
} |
|
|
|
|
|
|
|
LogManager.logInfo(TAG, "485连接诊断完成"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取485串口状态(即用即连模式) |
|
|
|
* @return 串口状态描述 |
|
|
|
*/ |
|
|
|
public String get485Status() { |
|
|
|
String status = "串口状态: 即用即连模式" + |
|
|
|
", 路径: " + DEFAULT_SERIAL_PORT_PATH + |
|
|
|
", 波特率: " + DEFAULT_BAUD_RATE + |
|
|
|
", 485模式: " + (gateCamera485OxOn ? "已启用" : "未启用"); |
|
|
|
|
|
|
|
LogManager.logInfo(TAG, status); |
|
|
|
return status; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 关闭485串口(兼容旧接口) |
|
|
|
*/ |
|
|
|
public void close485SerialPort() { |
|
|
|
LogManager.logInfo(TAG, "485串口即用即连模式无需手动关闭"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 释放资源 |
|
|
|
* 关闭并清理串口资源 |
|
|
|
* @param serialPortManager 串口管理器 |
|
|
|
*/ |
|
|
|
public void release() { |
|
|
|
LogManager.logInfo(TAG, "释放Ox485资源(即用即连模式)"); |
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// ========== 删除所有懒加载连接管理相关方法 ========== |
|
|
|
// 删除initConnectionCheckTask、startConnectionCheck、stopConnectionCheck、 |
|
|
|
// ensureConnection、createConnection、retryConnection、markSuccessfulCommunication、 |
|
|
|
// isSerialPortReallyOpen等方法 |
|
|
|
|
|
|
|
/** |
|
|
|
* HEX字符串转字节数组 |
|
|
|
* @param hexString HEX字符串 |
|
|
|