| | |
| | | package chushihua; |
| | | |
| | | import chuankou.Sendmsg; |
| | | import dialog.Errlog; |
| | | import home.Fkj; |
| | | import home.MachineConfig; |
| | | import publicway.QueryData; |
| | | import xitongshezhi.Fkj; |
| | | import xitongshezhi.SystemDebugDialog; |
| | | |
| | | import java.util.Map; |
| | |
| | | * 轮询查询类 - 优化版本 |
| | | * 用于定时向所有卡槽发送查询指令 |
| | | * 支持暂停和恢复功能,检查串口连接状态 |
| | | * 新增:不同卡槽状态使用不同查询频率 |
| | | */ |
| | | 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<Integer, String> 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); |
| | | } |
| | | 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; // 默认轮询间隔 |
| | | public static boolean sendChaxunzhiling=true;//是否向串口发送查询指令 |
| | | |
| | | public static boolean isSendChaxunzhiling() { |
| | | return sendChaxunzhiling; |
| | | } |
| | | |
| | | public static void setSendChaxunzhiling(boolean sendChaxunzhiling) { |
| | | lunxun.sendChaxunzhiling = sendChaxunzhiling; |
| | | } |
| | | |
| | | // 卡槽相关常量 |
| | | 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<Integer, String> queryCommandCache = new ConcurrentHashMap<>(); |
| | | |
| | | // 调试模式控制 |
| | | public static boolean DEBUG_ENABLED = false; |
| | | |
| | | // 新增:不同状态卡槽的查询频率控制 |
| | | private static final int NO_CARD_QUERY_INTERVAL = 100; // 无卡卡槽查询间隔:100ms |
| | | private static final int HAS_CARD_QUERY_INTERVAL = 10000; // 有卡卡槽查询间隔:10秒 |
| | | private static final Map<Integer, Long> lastQueryTimeMap = new ConcurrentHashMap<>(); // 记录每个卡槽的最后查询时间 |
| | | |
| | | /** |
| | | * 检查串口连接状态 - 优化版本,添加重试机制 |
| | | * @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 { |
| | | Errlog.logOperation("串口连接失败 - 串口未打开"); |
| | | serialConnected = false; |
| | | } |
| | | } catch (Exception e) { |
| | | Errlog.logOperation("串口连接检查异常: " + 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()) { |
| | | Errlog.logOperation("串口未连接,无法启动轮询查询"); |
| | | return false; |
| | | } |
| | | |
| | | // 从配置中获取轮询间隔 |
| | | loadPollingIntervalFromConfig(); |
| | | |
| | | // 初始化最后查询时间记录 |
| | | initializeLastQueryTimes(); |
| | | |
| | | isRunning = true; |
| | | isPaused = false; |
| | | shouldStop.set(false); |
| | | |
| | | try { |
| | | pollingThread = new Thread(new PollingTask(), "CardSlot-Polling-Thread"); |
| | | pollingThread.setDaemon(true); |
| | | pollingThread.start(); |
| | | return true; |
| | | } catch (Exception e) { |
| | | Errlog.logOperation("启动轮询查询线程时发生异常: " + e.getMessage()); |
| | | isRunning = false; |
| | | shouldStop.set(true); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 初始化最后查询时间记录 |
| | | */ |
| | | private static void initializeLastQueryTimes() { |
| | | lastQueryTimeMap.clear(); |
| | | for (int i = MIN_SLOT; i <= MAX_SLOT; i++) { |
| | | lastQueryTimeMap.put(i, 0L); // 初始化为0,表示从未查询过 |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 停止轮询查询 - 修复版本 |
| | | * @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()) { |
| | | Errlog.logOperation("轮询线程未在3秒内停止,标记为守护线程并忽略"); |
| | | // 不强制停止,而是确保它是守护线程 |
| | | pollingThread.setDaemon(true); |
| | | } |
| | | } catch (InterruptedException e) { |
| | | Errlog.logOperation("停止轮询查询时被中断: " + e.getMessage()); |
| | | Thread.currentThread().interrupt(); |
| | | } catch (Exception e) { |
| | | Errlog.logOperation("停止轮询线程时发生异常: " + 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()) { |
| | | Errlog.logOperation("串口未连接,无法恢复轮询查询"); |
| | | 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) { |
| | | Errlog.logOperation("轮询间隔不能小于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) { |
| | | Errlog.logOperation("加载轮询间隔配置失败: " + 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 { |
| | | |
| | | // System.out.println("查询中.....线程"); |
| | | // 检查是否暂停 |
| | | if (isPaused) { |
| | | synchronized (lunxun.class) { |
| | | while (isPaused && isRunning && !shouldStop.get()) { |
| | | lunxun.class.wait(1000); // 等待1秒或直到被唤醒 |
| | | } |
| | | } |
| | | continue; |
| | | } |
| | | |
| | | // 定期检查串口连接状态(每10次循环检查一次) |
| | | if (currentIndex % 10 == 0 && !checkSerialConnectionWithRetry()) { |
| | | Errlog.logOperation("串口连接断开,暂停轮询"); |
| | | pausePolling(); |
| | | continue; |
| | | } |
| | | |
| | | // 获取卡槽数组 |
| | | Fkj[] slotArray = SlotManager.getSlotArray(); |
| | | if (slotArray == null || slotArray.length == 0) { |
| | | Errlog.logOperation("卡槽数组未初始化"); |
| | | Thread.sleep(pollingInterval); |
| | | continue; |
| | | } |
| | | |
| | | // 新增:根据卡槽状态和查询频率决定是否发送查询 |
| | | boolean sentQuery = false; |
| | | long currentTime = System.currentTimeMillis(); |
| | | |
| | | // 遍历卡槽,寻找需要查询的卡槽 |
| | | for (int i = 0; i < slotArray.length && !sentQuery; i++) { |
| | | int slotIndex = (currentIndex + i) % slotArray.length; |
| | | Fkj slot = slotArray[slotIndex]; |
| | | if (slot != null) { |
| | | String hasCard = slot.getHasCard(); |
| | | int slotNumber = slotIndex + 1; |
| | | Long lastQueryTime = lastQueryTimeMap.get(slotNumber); |
| | | |
| | | // 确定查询间隔:只有hasCard="1"的卡槽使用10秒间隔,其他情况(包括"-1")都使用100ms间隔 |
| | | int queryInterval = "1".equals(hasCard) ? HAS_CARD_QUERY_INTERVAL : NO_CARD_QUERY_INTERVAL; |
| | | |
| | | // 检查是否达到查询时间 |
| | | if (lastQueryTime == null || currentTime - lastQueryTime >= queryInterval) { |
| | | if (sendQueryToSlot(slotNumber)) { |
| | | // 更新最后查询时间 |
| | | lastQueryTimeMap.put(slotNumber, currentTime); |
| | | sentQuery = true; |
| | | consecutiveFailures = 0; |
| | | |
| | | // 成功发送查询后,等待100ms再继续下一个查询 |
| | | Thread.sleep(100); |
| | | |
| | | if (DEBUG_ENABLED) { |
| | | String status; |
| | | if ("1".equals(hasCard)) { |
| | | status = "有卡"; |
| | | } else if ("-1".equals(hasCard)) { |
| | | status = "未知"; |
| | | } else { |
| | | status = "无卡"; |
| | | } |
| | | if (DEBUG_ENABLED) { |
| | | StringBuilder debugMsg = new StringBuilder(50); |
| | | debugMsg.append("Slot ").append(slotNumber) |
| | | .append(" (").append(status).append(") 查询成功,间隔: ") |
| | | .append(queryInterval).append("ms\n"); |
| | | SystemDebugDialog.appendAsciiData(debugMsg.toString()); |
| | | } |
| | | } |
| | | } else { |
| | | consecutiveFailures++; |
| | | if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) { |
| | | Errlog.logOperation("lunxun连续失败次数过多,暂停轮询"); |
| | | pausePolling(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 更新当前索引 |
| | | currentIndex = (currentIndex + 1) % slotArray.length; |
| | | |
| | | // 如果没有发送查询,等待一段时间再继续 |
| | | if (!sentQuery) { |
| | | Thread.sleep(pollingInterval); |
| | | } |
| | | |
| | | } catch (InterruptedException e) { |
| | | //System.out.println("轮询查询线程被中断"); |
| | | Thread.currentThread().interrupt(); |
| | | break; |
| | | } catch (Exception e) { |
| | | Errlog.logOperation("轮询查询过程中发生异常: " + 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); |
| | | // System.out.println("指令是:"+queryCommand); |
| | | if (DEBUG_ENABLED) { |
| | | SystemDebugDialog.appendAsciiData("send to "+slotNumber+" queryCommand"); |
| | | } |
| | | |
| | | if (queryCommand != null && !queryCommand.trim().isEmpty()) { |
| | | // 发送到串口 |
| | | |
| | | if(sendChaxunzhiling) { |
| | | boolean sendResult = Sendmsg.sendMessage(queryCommand); |
| | | if (sendResult) { |
| | | return true; |
| | | } else { |
| | | if (DEBUG_ENABLED) { |
| | | SystemDebugDialog.appendAsciiData(slotNumber+" Send query command to card slot err"); |
| | | } |
| | | // 发送失败可能是串口断开,更新连接状态 |
| | | serialConnected = false; |
| | | return false; |
| | | } |
| | | }else { |
| | | return false; |
| | | } |
| | | } else { |
| | | Errlog.logOperation("生成的查询指令为空,卡槽: " + slotNumber); |
| | | return false; |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | Errlog.logOperation("发送查询指令到卡槽 " + 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) { |
| | | Errlog.logOperation("卡槽编号必须在" + MIN_SLOT + "-" + MAX_SLOT + "之间"); |
| | | return false; |
| | | } |
| | | |
| | | // 检查串口连接 |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | Errlog.logOperation("串口未连接,无法发送查询指令"); |
| | | return false; |
| | | } |
| | | |
| | | try { |
| | | // 使用缓存的查询指令 |
| | | String queryCommand = getCachedQueryCommand(slotNumber); |
| | | |
| | | if (queryCommand != null && !queryCommand.trim().isEmpty()) { |
| | | // 发送到串口 |
| | | boolean sendResult = Sendmsg.sendMessage(queryCommand); |
| | | |
| | | if (sendResult) { |
| | | // 更新最后查询时间 |
| | | lastQueryTimeMap.put(slotNumber, System.currentTimeMillis()); |
| | | |
| | | if (DEBUG_ENABLED) { |
| | | //System.out.println("立即查询成功 - 卡槽 " + slotNumber); |
| | | } |
| | | return true; |
| | | } else { |
| | | Errlog.logOperation("立即查询失败 - 发送指令到卡槽 " + slotNumber + " 失败"); |
| | | return false; |
| | | } |
| | | } else { |
| | | Errlog.logOperation("立即查询失败 - 生成的查询指令为空,卡槽: " + slotNumber); |
| | | return false; |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | Errlog.logOperation("立即查询卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 立即向所有卡槽发送查询指令(批量)- 优化版本 |
| | | * @return 成功发送的指令数量 |
| | | */ |
| | | public static int sendImmediateQueryToAll() { |
| | | // 检查串口连接 |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | Errlog.logOperation("串口未连接,无法发送批量查询指令"); |
| | | return 0; |
| | | } |
| | | |
| | | int successCount = 0; |
| | | int batchSize = 5; // 每批次发送5个查询 |
| | | int totalSlots = MAX_SLOT - MIN_SLOT + 1; |
| | | long currentTime = System.currentTimeMillis(); |
| | | |
| | | //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++; |
| | | // 更新最后查询时间 |
| | | lastQueryTimeMap.put(slot, currentTime); |
| | | } |
| | | } |
| | | |
| | | // 批次间间隔,避免串口拥堵 |
| | | 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 { |
| | | Errlog.logOperation("串口连接状态已设置为: 未连接"); |
| | | // 如果串口断开且轮询正在运行,自动暂停轮询 |
| | | 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(); |
| | | |
| | | // 统计不同状态的卡槽数量 |
| | | int noCardCount = 0; |
| | | int hasCardCount = 0; |
| | | Fkj[] slotArray = SlotManager.getSlotArray(); |
| | | if (slotArray != null) { |
| | | for (Fkj slot : slotArray) { |
| | | if (slot != null && "1".equals(slot.getHasCard())) { |
| | | hasCardCount++; |
| | | } else { |
| | | noCardCount++; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return String.format("轮询状态: %s, 串口: %s, 间隔: %dms, 指令缓存: %d, 卡槽范围: %d-%d, 无卡: %d(100ms), 有卡: %d(10s)", |
| | | status, serialStatus, pollingInterval, cacheSize, MIN_SLOT, MAX_SLOT, |
| | | noCardCount, hasCardCount); |
| | | } |
| | | |
| | | /** |
| | | * 直接设置轮询暂停状态(供其他类调用) |
| | | * @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()) { |
| | | Errlog.logOperation("串口未连接,无法恢复轮询查询"); |
| | | 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() { |
| | | long currentTime = System.currentTimeMillis(); |
| | | int overdueNoCard = 0; |
| | | int overdueHasCard = 0; |
| | | |
| | | Fkj[] slotArray = SlotManager.getSlotArray(); |
| | | if (slotArray != null) { |
| | | for (int i = 0; i < slotArray.length; i++) { |
| | | Fkj slot = slotArray[i]; |
| | | if (slot != null) { |
| | | int slotNumber = i + 1; |
| | | Long lastQueryTime = lastQueryTimeMap.get(slotNumber); |
| | | if (lastQueryTime != null) { |
| | | String hasCard = slot.getHasCard(); |
| | | int queryInterval = "1".equals(hasCard) ? HAS_CARD_QUERY_INTERVAL : NO_CARD_QUERY_INTERVAL; |
| | | if (currentTime - lastQueryTime > queryInterval) { |
| | | if ("1".equals(hasCard)) { |
| | | overdueHasCard++; |
| | | } else { |
| | | overdueNoCard++; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | return String.format("查询指令缓存大小: %d, 轮询间隔: %dms, 超时无卡: %d, 超时有卡: %d", |
| | | queryCommandCache.size(), pollingInterval, overdueNoCard, overdueHasCard); |
| | | } |
| | | |
| | | /** |
| | | * 设置无卡卡槽查询间隔 |
| | | * @param interval 查询间隔(毫秒) |
| | | */ |
| | | public static void setNoCardQueryInterval(int interval) { |
| | | if (interval < 10) { |
| | | Errlog.logOperation("无卡卡槽查询间隔不能小于10ms"); |
| | | return; |
| | | } |
| | | // 注意:这里只是设置常量,实际运行时需要重新启动轮询才能生效 |
| | | //System.out.println("无卡卡槽查询间隔已设置为: " + interval + "ms"); |
| | | } |
| | | |
| | | /** |
| | | * 设置有卡卡槽查询间隔 |
| | | * @param interval 查询间隔(毫秒) |
| | | */ |
| | | public static void setHasCardQueryInterval(int interval) { |
| | | if (interval < 1000) { |
| | | Errlog.logOperation("有卡卡槽查询间隔不能小于1000ms"); |
| | | return; |
| | | } |
| | | // 注意:这里只是设置常量,实际运行时需要重新启动轮询才能生效 |
| | | //System.out.println("有卡卡槽查询间隔已设置为: " + interval + "ms"); |
| | | } |
| | | |
| | | public static boolean isDEBUG_ENABLED() { |
| | | return DEBUG_ENABLED; |