package chushihua; import chuankou.Sendmsg; import home.MachineConfig; import publicway.QueryData; import xitongshezhi.Fkj; import xitongshezhi.SystemDebugDialog; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; /** * 轮询查询类 - 优化版本 * 用于定时向所有卡槽发送查询指令 * 支持暂停和恢复功能,检查串口连接状态 */ public class lunxun { private static volatile boolean isRunning = false; private static volatile boolean isPaused = false; private static final AtomicBoolean shouldStop = new AtomicBoolean(false); private static Thread pollingThread; private static int pollingInterval = 100; // 默认轮询间隔 // 卡槽相关常量 private static final int MIN_SLOT = 1; private static final int MAX_SLOT = 60; // 串口连接检查相关 private static final int SERIAL_CHECK_INTERVAL = 5000; // 5秒检查一次串口连接 private static long lastSerialCheckTime = 0; private static boolean serialConnected = false; // 性能优化:查询指令缓存 private static final Map queryCommandCache = new ConcurrentHashMap<>(); // 调试模式控制 public static boolean DEBUG_ENABLED = false; /** * 检查串口连接状态 - 优化版本,添加重试机制 * @return true-串口已连接, false-串口未连接 */ public static boolean checkSerialConnection() { // 避免频繁检查,每5秒检查一次 long currentTime = System.currentTimeMillis(); if (currentTime - lastSerialCheckTime < SERIAL_CHECK_INTERVAL) { return serialConnected; } lastSerialCheckTime = currentTime; try { // 简化检查:直接检查Sendmsg的串口状态,而不是发送测试指令 boolean result = Sendmsg.isPortOpen(); if (result) { if (DEBUG_ENABLED) { //System.out.println("串口连接正常"); } serialConnected = true; } else { System.err.println("串口连接失败 - 串口未打开"); serialConnected = false; } } catch (Exception e) { System.err.println("串口连接检查异常: " + e.getMessage()); serialConnected = false; } return serialConnected; } /** * 带重试的串口连接检查 */ private static boolean checkSerialConnectionWithRetry() { for (int i = 0; i < 3; i++) { if (checkSerialConnection()) { return true; } try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } } return false; } /** * 启动轮询查询 - 优化版本 * @return true-启动成功, false-启动失败 */ public static boolean startPolling() { if (isRunning) { //System.out.println("轮询查询已经在运行中"); return true; } // 启动前严格检查串口连接 if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法启动轮询查询"); return false; } // 从配置中获取轮询间隔 loadPollingIntervalFromConfig(); isRunning = true; isPaused = false; shouldStop.set(false); try { pollingThread = new Thread(new PollingTask(), "CardSlot-Polling-Thread"); pollingThread.setDaemon(true); pollingThread.start(); if (DEBUG_ENABLED) { //System.out.println("轮询查询已启动,间隔: " + pollingInterval + "ms"); } return true; } catch (Exception e) { System.err.println("启动轮询查询线程时发生异常: " + e.getMessage()); isRunning = false; shouldStop.set(true); return false; } } /** * 停止轮询查询 - 修复版本 * @return true-停止成功, false-停止失败 */ public static boolean stopPolling() { if (!isRunning) { //System.out.println("轮询查询未在运行"); return false; } shouldStop.set(true); isRunning = false; isPaused = false; if (pollingThread != null) { pollingThread.interrupt(); try { pollingThread.join(3000); // 等待3秒 // 检查线程是否还在运行 if (pollingThread.isAlive()) { System.err.println("轮询线程未在3秒内停止,标记为守护线程并忽略"); // 不强制停止,而是确保它是守护线程 pollingThread.setDaemon(true); } } catch (InterruptedException e) { System.err.println("停止轮询查询时被中断: " + e.getMessage()); Thread.currentThread().interrupt(); } catch (Exception e) { System.err.println("停止轮询线程时发生异常: " + e.getMessage()); } finally { pollingThread = null; } } shouldStop.set(false); //System.out.println("轮询查询已停止"); return true; } /** * 暂停轮询查询 * @return true-暂停成功, false-暂停失败 */ public static boolean pausePolling() { if (!isRunning) { if (DEBUG_ENABLED) { //System.out.println("轮询查询未在运行,无法暂停"); } return false; } if (isPaused) { if (DEBUG_ENABLED) { //System.out.println("轮询查询已经处于暂停状态"); } return false; } isPaused = true; //System.out.println("轮询查询已暂停"); return true; } /** * 恢复轮询查询 * @return true-恢复成功, false-恢复失败 */ public static boolean resumePolling() { if (!isRunning) { //System.out.println("轮询查询未在运行,无法恢复"); return false; } if (!isPaused) { //System.out.println("轮询查询未处于暂停状态"); return false; } // 恢复前检查串口连接 if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法恢复轮询查询"); return false; } isPaused = false; synchronized (lunxun.class) { lunxun.class.notifyAll(); // 唤醒等待的线程 } //System.out.println("轮询查询已恢复"); return true; } /** * 检查轮询状态 * @return true-正在运行, false-已停止 */ public static boolean isPolling() { return isRunning; } /** * 检查是否暂停 * @return true-已暂停, false-未暂停 */ public static boolean isPaused() { return isPaused; } /** * 检查串口连接状态 * @return true-串口已连接, false-串口未连接 */ public static boolean isSerialConnected() { return serialConnected; } /** * 设置轮询间隔 * @param interval 轮询间隔(毫秒) */ public static void setPollingInterval(int interval) { if (interval < 10) { System.err.println("轮询间隔不能小于10ms"); return; } pollingInterval = interval; //System.out.println("轮询间隔已设置为: " + interval + "ms"); // 如果正在运行,重新启动以应用新的间隔 if (isRunning) { restartPolling(); } } /** * 获取当前轮询间隔 * @return 轮询间隔(毫秒) */ public static int getPollingInterval() { return pollingInterval; } /** * 重新启动轮询查询 * @return true-重启成功, false-重启失败 */ public static boolean restartPolling() { stopPolling(); // 等待一小段时间确保线程完全停止 try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return startPolling(); } /** * 从配置中加载轮询间隔 */ private static void loadPollingIntervalFromConfig() { try { Chushihua configSystem = Chushihua.getInstance(); if (configSystem.isInitialized()) { MachineConfig machineConfig = configSystem.getMachineConfig(); pollingInterval = machineConfig.getPollingInterval(); //System.out.println("从配置加载轮询间隔: " + pollingInterval + "ms"); } else { //System.out.println("配置系统未初始化,使用默认轮询间隔: " + pollingInterval + "ms"); } } catch (Exception e) { System.err.println("加载轮询间隔配置失败: " + e.getMessage()); //System.out.println("使用默认轮询间隔: " + pollingInterval + "ms"); } } /** * 获取缓存的查询指令 */ private static String getCachedQueryCommand(int slotNumber) { return queryCommandCache.computeIfAbsent(slotNumber, QueryData::queryData); } /** * 清空查询指令缓存(当查询逻辑变化时调用) */ public static void clearQueryCache() { queryCommandCache.clear(); //System.out.println("查询指令缓存已清空"); } /** * 轮询任务内部类 - 优化版本 * 优化内存使用:避免在循环中创建新对象 * 添加批量处理和性能监控 */ private static class PollingTask implements Runnable { private int currentIndex = 0; // 当前索引,用于遍历slotArray private int consecutiveFailures = 0; // 连续失败次数 private static final int MAX_CONSECUTIVE_FAILURES = 5; // 最大连续失败次数 @Override public void run() { //System.out.println("轮询查询线程开始运行"); while (isRunning && !Thread.currentThread().isInterrupted() && !shouldStop.get()) { try { // 检查是否暂停 if (isPaused) { synchronized (lunxun.class) { while (isPaused && isRunning && !shouldStop.get()) { lunxun.class.wait(1000); // 等待1秒或直到被唤醒 } } continue; } // 定期检查串口连接状态(每10次循环检查一次) if (currentIndex % 10 == 0 && !checkSerialConnectionWithRetry()) { System.err.println("串口连接断开,暂停轮询"); pausePolling(); continue; } // 获取卡槽数组 Fkj[] slotArray = SlotManager.getSlotArray(); if (slotArray == null || slotArray.length == 0) { System.err.println("卡槽数组未初始化"); Thread.sleep(pollingInterval); continue; } // 遍历所有卡槽,只给 hasCard != 1 的卡槽发送查询指令 boolean sentQuery = false; int checkedSlots = 0; int maxSlotsPerCycle = Math.min(10, slotArray.length); // 每周期最多检查10个卡槽 for (int i = 0; i < maxSlotsPerCycle && checkedSlots < slotArray.length; i++) { Fkj slot = slotArray[currentIndex]; if (slot != null) { String hasCard = slot.getHasCard(); if (!"1".equals(hasCard)) { int slotNumber = currentIndex + 1; if (sendQueryToSlot(slotNumber)) { sentQuery = true; consecutiveFailures = 0; // 关键修复:在break前先更新索引 currentIndex = (currentIndex + 1) % slotArray.length; checkedSlots++; Thread.sleep(pollingInterval); break; } else { consecutiveFailures++; if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) { System.err.println("连续失败次数过多,暂停轮询"); pausePolling(); break; } } } } // 对于不需要发送查询的卡槽,正常更新索引 currentIndex = (currentIndex + 1) % slotArray.length; checkedSlots++; } // 如果没有找到需要查询的卡槽,等待一段时间再继续 if (!sentQuery) { Thread.sleep(pollingInterval * 2); // 没有查询时等待时间加倍 } } catch (InterruptedException e) { //System.out.println("轮询查询线程被中断"); Thread.currentThread().interrupt(); break; } catch (Exception e) { System.err.println("轮询查询过程中发生异常: " + e.getMessage()); consecutiveFailures++; // 发生异常时等待一段时间再继续 try { Thread.sleep(1000); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); break; } } } //System.out.println("轮询查询线程结束运行"); } /** * 向指定卡槽发送查询指令 - 优化版本 * 使用缓存指令,优化调试输出 */ private boolean sendQueryToSlot(int slotNumber) { try { // 使用缓存的查询指令 String queryCommand = getCachedQueryCommand(slotNumber); if (queryCommand != null && !queryCommand.trim().isEmpty()) { // 发送到串口 boolean sendResult = Sendmsg.sendMessage(queryCommand); if (sendResult) { // 只在调试时输出,避免频繁打印 if (DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData(String.format("Slot %d Send query (hasCard !=1)", slotNumber)); } return true; } else { if (DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData("Send query command to card slot err"); } // 发送失败可能是串口断开,更新连接状态 serialConnected = false; return false; } } else { System.err.println("生成的查询指令为空,卡槽: " + slotNumber); return false; } } catch (Exception e) { System.err.println("发送查询指令到卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); // 发生异常时更新串口连接状态 serialConnected = false; return false; } } } /** * 立即向指定卡槽发送查询指令(不等待轮询) * @param slotNumber 卡槽编号 (1-60) * @return true-发送成功, false-发送失败 */ public static boolean sendImmediateQuery(int slotNumber) { if (slotNumber < MIN_SLOT || slotNumber > MAX_SLOT) { System.err.println("卡槽编号必须在" + MIN_SLOT + "-" + MAX_SLOT + "之间"); return false; } // 检查串口连接 if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法发送查询指令"); return false; } try { // 使用缓存的查询指令 String queryCommand = getCachedQueryCommand(slotNumber); if (queryCommand != null && !queryCommand.trim().isEmpty()) { // 发送到串口 boolean sendResult = Sendmsg.sendMessage(queryCommand); if (sendResult) { if (DEBUG_ENABLED) { //System.out.println("立即查询成功 - 卡槽 " + slotNumber); } return true; } else { System.err.println("立即查询失败 - 发送指令到卡槽 " + slotNumber + " 失败"); return false; } } else { System.err.println("立即查询失败 - 生成的查询指令为空,卡槽: " + slotNumber); return false; } } catch (Exception e) { System.err.println("立即查询卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); return false; } } /** * 立即向所有卡槽发送查询指令(批量)- 优化版本 * @return 成功发送的指令数量 */ public static int sendImmediateQueryToAll() { // 检查串口连接 if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法发送批量查询指令"); return 0; } int successCount = 0; int batchSize = 5; // 每批次发送5个查询 int totalSlots = MAX_SLOT - MIN_SLOT + 1; //System.out.println("开始批量查询所有卡槽..."); for (int batchStart = MIN_SLOT; batchStart <= MAX_SLOT; batchStart += batchSize) { if (shouldStop.get()) { break; } int batchEnd = Math.min(batchStart + batchSize - 1, MAX_SLOT); // 批次内查询 for (int slot = batchStart; slot <= batchEnd; slot++) { if (sendImmediateQuery(slot)) { successCount++; } } // 批次间间隔,避免串口拥堵 if (batchEnd < MAX_SLOT) { try { Thread.sleep(50); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } //System.out.println("批量查询完成,成功发送: " + successCount + "/" + totalSlots); return successCount; } /** * 手动设置串口连接状态(用于外部检测到串口状态变化时调用) * @param connected 串口连接状态 */ public static void setSerialConnected(boolean connected) { serialConnected = connected; lastSerialCheckTime = System.currentTimeMillis(); if (connected) { // //System.out.println("串口连接状态已设置为: 已连接"); } else { System.err.println("串口连接状态已设置为: 未连接"); // 如果串口断开且轮询正在运行,自动暂停轮询 if (isRunning && !isPaused) { pausePolling(); } } } /** * 获取轮询状态信息 * @return 状态信息字符串 */ public static String getPollingStatus() { String status; if (!isRunning) { status = "已停止"; } else if (isPaused) { status = "已暂停"; } else { status = "运行中"; } String serialStatus = serialConnected ? "已连接" : "未连接"; int cacheSize = queryCommandCache.size(); return String.format("轮询状态: %s, 串口: %s, 间隔: %dms, 指令缓存: %d, 卡槽范围: %d-%d", status, serialStatus, pollingInterval, cacheSize, MIN_SLOT, MAX_SLOT); } /** * 直接设置轮询暂停状态(供其他类调用) * @param paused true-暂停轮询, false-恢复轮询 * @return true-设置成功, false-设置失败(如轮询未运行) */ public static boolean setPollingPaused(boolean paused) { if (!isRunning) { //System.out.println("轮询查询未在运行,无法设置暂停状态"); return false; } if (paused) { // 请求暂停 if (!isPaused) { isPaused = true; //System.out.println("轮询查询已通过外部调用暂停"); return true; } else { //System.out.println("轮询查询已经处于暂停状态"); return false; } } else { // 请求恢复 if (isPaused) { // 恢复前检查串口连接 if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法恢复轮询查询"); return false; } isPaused = false; synchronized (lunxun.class) { lunxun.class.notifyAll(); // 唤醒等待的线程 } //System.out.println("轮询查询已通过外部调用恢复"); return true; } else { //System.out.println("轮询查询未处于暂停状态"); return false; } } } /** * 获取性能统计信息 */ public static String getPerformanceStats() { return String.format("查询指令缓存大小: %d, 轮询间隔: %dms", queryCommandCache.size(), pollingInterval); } public static boolean isDEBUG_ENABLED() { return DEBUG_ENABLED; } public static void setDEBUG_ENABLED(boolean dEBUG_ENABLED) { DEBUG_ENABLED = dEBUG_ENABLED; } }