张世豪
8 小时以前 a6077217e25f5804027194a5c2848e773eda1abd
src/chushihua/lunxun.java
@@ -1,9 +1,10 @@
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;
@@ -14,6 +15,7 @@
 * 轮询查询类 - 优化版本
 * 用于定时向所有卡槽发送查询指令
 * 支持暂停和恢复功能,检查串口连接状态
 * 新增:不同卡槽状态使用不同查询频率
 */
public class lunxun {
    private static volatile boolean isRunning = false;
@@ -21,6 +23,15 @@
    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;
@@ -36,6 +47,11 @@
    
    // 调试模式控制
    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<>(); // 记录每个卡槽的最后查询时间
    
    /**
     * 检查串口连接状态 - 优化版本,添加重试机制
@@ -60,11 +76,11 @@
                }
                serialConnected = true;
            } else {
                System.err.println("串口连接失败 - 串口未打开");
            Errlog.logOperation("串口连接失败 - 串口未打开");
                serialConnected = false;
            }
        } catch (Exception e) {
            System.err.println("串口连接检查异常: " + e.getMessage());
         Errlog.logOperation("串口连接检查异常: " + e.getMessage());
            serialConnected = false;
        }
        
@@ -101,12 +117,15 @@
        
        // 启动前严格检查串口连接
        if (!checkSerialConnectionWithRetry()) {
            System.err.println("串口未连接,无法启动轮询查询");
         Errlog.logOperation("串口未连接,无法启动轮询查询");
            return false;
        }
        
        // 从配置中获取轮询间隔
        loadPollingIntervalFromConfig();
      // 初始化最后查询时间记录
      initializeLastQueryTimes();
        
        isRunning = true;
        isPaused = false;
@@ -118,10 +137,20 @@
            pollingThread.start(); 
            return true;
        } catch (Exception e) {
            System.err.println("启动轮询查询线程时发生异常: " + e.getMessage());
         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,表示从未查询过
        }
    }
    
@@ -145,22 +174,22 @@
                pollingThread.join(3000); // 等待3秒
                // 检查线程是否还在运行
                if (pollingThread.isAlive()) {
                    System.err.println("轮询线程未在3秒内停止,标记为守护线程并忽略");
               Errlog.logOperation("轮询线程未在3秒内停止,标记为守护线程并忽略");
                    // 不强制停止,而是确保它是守护线程
                    pollingThread.setDaemon(true);
                }
            } catch (InterruptedException e) {
                System.err.println("停止轮询查询时被中断: " + e.getMessage());
            Errlog.logOperation("停止轮询查询时被中断: " + e.getMessage());
                Thread.currentThread().interrupt();
            } catch (Exception e) {
                System.err.println("停止轮询线程时发生异常: " + e.getMessage());
            Errlog.logOperation("停止轮询线程时发生异常: " + e.getMessage());
            } finally {
                pollingThread = null;
            }
        }
        
        shouldStop.set(false);
        //System.out.println("轮询查询已停止");
      //System.out.println("轮询查询已停止 - 串口数据接收不受影响");
        return true;
    }
    
@@ -184,7 +213,7 @@
        }
        
        isPaused = true;
        //System.out.println("轮询查询已暂停");
      //System.out.println("轮询查询已暂停 - 仅停止发送查询指令");
        return true;
    }
    
@@ -205,7 +234,7 @@
        
        // 恢复前检查串口连接
        if (!checkSerialConnectionWithRetry()) {
            System.err.println("串口未连接,无法恢复轮询查询");
         Errlog.logOperation("串口未连接,无法恢复轮询查询");
            return false;
        }
        
@@ -247,7 +276,7 @@
     */
    public static void setPollingInterval(int interval) {
        if (interval < 10) {
            System.err.println("轮询间隔不能小于10ms");
         Errlog.logOperation("轮询间隔不能小于10ms");
            return;
        }
        
@@ -299,7 +328,7 @@
                //System.out.println("配置系统未初始化,使用默认轮询间隔: " + pollingInterval + "ms");
            }
        } catch (Exception e) {
            System.err.println("加载轮询间隔配置失败: " + e.getMessage());
         Errlog.logOperation("加载轮询间隔配置失败: " + e.getMessage());
            //System.out.println("使用默认轮询间隔: " + pollingInterval + "ms");
        }
    }
@@ -321,9 +350,9 @@
    
    /**
     * 轮询任务内部类 - 优化版本
     * 优化内存使用:避免在循环中创建新对象
     * 添加批量处理和性能监控
    * 支持不同状态卡槽的不同查询频率
     */
    private static class PollingTask implements Runnable {
        private int currentIndex = 0; // 当前索引,用于遍历slotArray
        private int consecutiveFailures = 0; // 连续失败次数
@@ -335,6 +364,8 @@
            
            while (isRunning && !Thread.currentThread().isInterrupted() && !shouldStop.get()) {
                try {
               //                   System.out.println("查询中.....线程");
                    // 检查是否暂停
                    if (isPaused) {
                        synchronized (lunxun.class) {
@@ -347,7 +378,7 @@
                    
                    // 定期检查串口连接状态(每10次循环检查一次)
                    if (currentIndex % 10 == 0 && !checkSerialConnectionWithRetry()) {
                        System.err.println("串口连接断开,暂停轮询");
                  Errlog.logOperation("串口连接断开,暂停轮询");
                        pausePolling();
                        continue;
                    }
@@ -355,51 +386,69 @@
                    // 获取卡槽数组
                    Fkj[] slotArray = SlotManager.getSlotArray();
                    if (slotArray == null || slotArray.length == 0) {
                        System.err.println("卡槽数组未初始化");
                  Errlog.logOperation("卡槽数组未初始化");
                        Thread.sleep(pollingInterval);
                        continue;
                    }
                    
                    // 遍历所有卡槽,只给 hasCard != 1 的卡槽发送查询指令
               // 新增:根据卡槽状态和查询频率决定是否发送查询
                    boolean sentQuery = false;
                    int checkedSlots = 0;
                    int maxSlotsPerCycle = Math.min(10, slotArray.length); // 每周期最多检查10个卡槽
               long currentTime = System.currentTimeMillis();
                    
                    for (int i = 0; i < maxSlotsPerCycle && checkedSlots < slotArray.length; i++) {
                        Fkj slot = slotArray[currentIndex];
               // 遍历卡槽,寻找需要查询的卡槽
               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();
                            if (!"1".equals(hasCard)) {
                                int slotNumber = currentIndex + 1;
                     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;
                                    
                                    // 关键修复:在break前先更新索引
                                    currentIndex = (currentIndex + 1) % slotArray.length;
                                    checkedSlots++;
                           // 成功发送查询后,等待100ms再继续下一个查询
                           Thread.sleep(100);
                                    
                                    Thread.sleep(pollingInterval);
                                    break;
                           if (DEBUG_ENABLED) {
                              String status;
                              if ("1".equals(hasCard)) {
                                 status = "有卡";
                              } else if ("-1".equals(hasCard)) {
                                 status = "未知";
                              } else {
                                 status = "无卡";
                              }
                              SystemDebugDialog.appendAsciiData(
                                    String.format("Slot %d (%s) 查询成功,间隔: %dms\n",
                                          slotNumber, status, queryInterval));
                           }
                                } else {
                                    consecutiveFailures++;
                                    if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
                                        System.err.println("lunxun连续失败次数过多,暂停轮询");
                              Errlog.logOperation("lunxun连续失败次数过多,暂停轮询");
                                        pausePolling();
                                        break;
                                    }
                                }
                            }
                        }
                        // 对于不需要发送查询的卡槽,正常更新索引
                        currentIndex = (currentIndex + 1) % slotArray.length;
                        checkedSlots++;
                    }
                    
                    // 如果没有找到需要查询的卡槽,等待一段时间再继续
               // 更新当前索引
               currentIndex = (currentIndex + 1) % slotArray.length;
               // 如果没有发送查询,等待一段时间再继续
                    if (!sentQuery) {
                        Thread.sleep(pollingInterval * 2); // 没有查询时等待时间加倍
                  Thread.sleep(pollingInterval);
                    }
                    
                } catch (InterruptedException e) {
@@ -407,7 +456,7 @@
                    Thread.currentThread().interrupt();
                    break;
                } catch (Exception e) {
                    System.err.println("轮询查询过程中发生异常: " + e.getMessage());
               Errlog.logOperation("轮询查询过程中发生异常: " + e.getMessage());
                    consecutiveFailures++;
                    
                    // 发生异常时等待一段时间再继续
@@ -431,32 +480,36 @@
            try {
                // 使用缓存的查询指令
                String queryCommand = getCachedQueryCommand(slotNumber);
            // System.out.println("指令是:"+queryCommand);
            if (DEBUG_ENABLED) {
               SystemDebugDialog.appendAsciiData("send to "+slotNumber+" queryCommand");
            }
                
                if (queryCommand != null && !queryCommand.trim().isEmpty()) {
                    // 发送到串口
                    boolean sendResult = Sendmsg.sendMessage(queryCommand);
                    
               if(sendChaxunzhiling) {
                  boolean sendResult = Sendmsg.sendMessage(queryCommand);
                    if (sendResult) {
                        // 只在调试时输出,避免频繁打印
                        if (DEBUG_ENABLED) {
                            SystemDebugDialog.appendAsciiData(String.format("Slot %d Send query (hasCard !=1)\n", slotNumber));
                        }
                        return true;
                    } else {
                        if (DEBUG_ENABLED) {
                            SystemDebugDialog.appendAsciiData("Send query command to card slot err");
                        SystemDebugDialog.appendAsciiData(slotNumber+" Send query command to card slot err");
                        }
                        // 发送失败可能是串口断开,更新连接状态
                        serialConnected = false;
                        return false;
                    }
                } else {
                    System.err.println("生成的查询指令为空,卡槽: " + slotNumber);
                  return false;
               }
            } else {
               Errlog.logOperation("生成的查询指令为空,卡槽: " + slotNumber);
                    return false;
                }
                
            } catch (Exception e) {
                System.err.println("发送查询指令到卡槽 " + slotNumber + " 时发生异常: " + e.getMessage());
            Errlog.logOperation("发送查询指令到卡槽 " + slotNumber + " 时发生异常: " + e.getMessage());
                // 发生异常时更新串口连接状态
                serialConnected = false;
                return false;
@@ -471,13 +524,13 @@
     */
    public static boolean sendImmediateQuery(int slotNumber) {
        if (slotNumber < MIN_SLOT || slotNumber > MAX_SLOT) {
            System.err.println("卡槽编号必须在" + MIN_SLOT + "-" + MAX_SLOT + "之间");
         Errlog.logOperation("卡槽编号必须在" + MIN_SLOT + "-" + MAX_SLOT + "之间");
            return false;
        }
        
        // 检查串口连接
        if (!checkSerialConnectionWithRetry()) {
            System.err.println("串口未连接,无法发送查询指令");
         Errlog.logOperation("串口未连接,无法发送查询指令");
            return false;
        }
        
@@ -490,21 +543,24 @@
                boolean sendResult = Sendmsg.sendMessage(queryCommand);
                
                if (sendResult) {
               // 更新最后查询时间
               lastQueryTimeMap.put(slotNumber, System.currentTimeMillis());
                    if (DEBUG_ENABLED) {
                        //System.out.println("立即查询成功 - 卡槽 " + slotNumber);
                    }
                    return true;
                } else {
                    System.err.println("立即查询失败 - 发送指令到卡槽 " + slotNumber + " 失败");
               Errlog.logOperation("立即查询失败 - 发送指令到卡槽 " + slotNumber + " 失败");
                    return false;
                }
            } else {
                System.err.println("立即查询失败 - 生成的查询指令为空,卡槽: " + slotNumber);
            Errlog.logOperation("立即查询失败 - 生成的查询指令为空,卡槽: " + slotNumber);
                return false;
            }
            
        } catch (Exception e) {
            System.err.println("立即查询卡槽 " + slotNumber + " 时发生异常: " + e.getMessage());
         Errlog.logOperation("立即查询卡槽 " + slotNumber + " 时发生异常: " + e.getMessage());
            return false;
        }
    }
@@ -516,13 +572,14 @@
    public static int sendImmediateQueryToAll() {
        // 检查串口连接
        if (!checkSerialConnectionWithRetry()) {
            System.err.println("串口未连接,无法发送批量查询指令");
         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("开始批量查询所有卡槽...");
        
@@ -537,6 +594,8 @@
            for (int slot = batchStart; slot <= batchEnd; slot++) {
                if (sendImmediateQuery(slot)) {
                    successCount++;
               // 更新最后查询时间
               lastQueryTimeMap.put(slot, currentTime);
                }
            }
            
@@ -566,7 +625,7 @@
        if (connected) {
//            //System.out.println("串口连接状态已设置为: 已连接");
        } else {
            System.err.println("串口连接状态已设置为: 未连接");
         Errlog.logOperation("串口连接状态已设置为: 未连接");
            // 如果串口断开且轮询正在运行,自动暂停轮询
            if (isRunning && !isPaused) {
                pausePolling();
@@ -591,8 +650,23 @@
        String serialStatus = serialConnected ? "已连接" : "未连接";
        int cacheSize = queryCommandCache.size();
        
        return String.format("轮询状态: %s, 串口: %s, 间隔: %dms, 指令缓存: %d, 卡槽范围: %d-%d",
                           status, serialStatus, pollingInterval, cacheSize, MIN_SLOT, MAX_SLOT);
      // 统计不同状态的卡槽数量
      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);
    }
    
    /**
@@ -621,7 +695,7 @@
            if (isPaused) {
                // 恢复前检查串口连接
                if (!checkSerialConnectionWithRetry()) {
                    System.err.println("串口未连接,无法恢复轮询查询");
               Errlog.logOperation("串口未连接,无法恢复轮询查询");
                    return false;
                }
                
@@ -642,8 +716,60 @@
     * 获取性能统计信息
     */
    public static String getPerformanceStats() {
        return String.format("查询指令缓存大小: %d, 轮询间隔: %dms",
                           queryCommandCache.size(), pollingInterval);
      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() {