liuwei 5 dni temu
rodzic
commit
776446ce22

+ 1 - 0
last_submitted_sn.txt

@@ -0,0 +1 @@
+0050010200173E5240017067171A02

+ 96 - 5
src/com/mes/ui/MesClient.java

@@ -75,6 +75,10 @@ public class MesClient extends JFrame {
     public static JTextField product_sn;
     public static JButton f_scan_data_bt_1;
     public static JButton f_start_bt;
+    public static JButton f_retest_bt;
+    /** 最近一次提交成功的工件码(再测一次用) */
+    public static String lastSubmittedSn = "";
+    private static final String LAST_SN_FILE = "last_submitted_sn.txt";
 
     public static String user20 = "";
     public static boolean mes_enable = true; // true=MES开启
@@ -362,6 +366,7 @@ public class MesClient extends JFrame {
         if (serialPortUtils != null && serialPortUtils.isOpen) {
             WorkTimer.startStopTimer();
         }
+        refreshRetestButton();
         MesClient.setMenuStatus("请扫工件码",0);
     }
 
@@ -373,16 +378,90 @@ public class MesClient extends JFrame {
         // 设备检测中(已进入测试)不允许再点启动
         if (enabled && mesStartFlag != null && mesStartFlag == 1) {
             f_start_bt.setEnabled(false);
+            refreshRetestButton();
             return;
         }
         f_start_bt.setEnabled(enabled);
+        refreshRetestButton();
+    }
+
+    /** 结果提交成功后保存最近工件码(内存 + 本地文件) */
+    public static void saveLastSubmittedSn(String sn) {
+        if (sn == null || sn.trim().isEmpty()) {
+            return;
+        }
+        lastSubmittedSn = sn.trim();
+        try {
+            java.io.FileWriter fw = new java.io.FileWriter(LAST_SN_FILE, false);
+            fw.write(lastSubmittedSn);
+            fw.close();
+            log.info("已保存再测工件码: {}", lastSubmittedSn);
+        } catch (Exception e) {
+            log.error("保存再测工件码失败: {}", e.getMessage());
+        }
+        refreshRetestButton();
+    }
+
+    /** 启动时加载上次提交的工件码 */
+    public static void loadLastSubmittedSn() {
+        try {
+            java.io.File f = new java.io.File(LAST_SN_FILE);
+            if (!f.exists()) {
+                return;
+            }
+            BufferedReader br = new BufferedReader(new java.io.FileReader(f));
+            String line = br.readLine();
+            br.close();
+            if (line != null && !line.trim().isEmpty()) {
+                lastSubmittedSn = line.trim();
+                log.info("已加载再测工件码: {}", lastSubmittedSn);
+            }
+        } catch (Exception e) {
+            log.error("加载再测工件码失败: {}", e.getMessage());
+        }
+        refreshRetestButton();
+    }
+
+    /** 空闲且有历史码时,「再测一次」可点 */
+    public static void refreshRetestButton() {
+        if (f_retest_bt == null) {
+            return;
+        }
+        boolean idle = work_status != null && work_status == 0
+                && (mesStartFlag == null || mesStartFlag == 0);
+        boolean hasSn = lastSubmittedSn != null && !lastSubmittedSn.trim().isEmpty();
+        f_retest_bt.setEnabled(idle && hasSn);
     }
 
     /**
-     * 扫码校验成功后:停止复位定时器,并按启动模式点亮启动或自动启动。
+     * 再测一次:回填上次提交工件码,走与扫码相同的校验流程。
+     */
+    public static void retestLastSn() {
+        if (lastSubmittedSn == null || lastSubmittedSn.trim().isEmpty()) {
+            setMenuStatus("没有可再测的工件码", -1);
+            return;
+        }
+        if (work_status != null && work_status == 1) {
+            setMenuStatus("当前已有工件在测,请先完成", -1);
+            return;
+        }
+        if (mesStartFlag != null && mesStartFlag == 1) {
+            setMenuStatus("检测中,无法再测", -1);
+            return;
+        }
+        product_sn.setText(lastSubmittedSn.trim());
+        scan_type = 1;
+        setMenuStatus("再测:正在校验工件码", 0);
+        scanBarcode2();
+    }
+
+    /**
+     * 扫码/质量校验成功后:停止复位定时器,并按启动模式点亮启动或自动启动。
+     * MES:在 checkQuality 返回 UD 时调用;本地无 MES:扫码本地校验通过后调用。
      */
     public static void onScanValidated() {
         WorkTimer.stopStopTimer();
+        refreshRetestButton();
         if (configParam != null && "自动启动".equals(configParam.getStartMode())) {
             doStartTest();
         } else {
@@ -404,7 +483,9 @@ public class MesClient extends JFrame {
         boolean ok = serialPortUtils != null && serialPortUtils.start();
         setStartButtonEnabled(false);
         if (ok) {
-            mesStartFlag = 1; // 已发启动,视为进入检测,启动按钮保持不可用
+            // 等轮询见到测试中(bit5=0)再置 mesStartFlag=1,避免沿用上一轮周期结束状态误收尾
+            mesStartFlag = 0;
+            refreshRetestButton();
             setMenuStatus("已启动,测试中", 0);
             result.setText("等待结果");
             result.setForeground(Color.GRAY);
@@ -806,14 +887,12 @@ public class MesClient extends JFrame {
             loadAteqProgramTimes();
             if(MesClient.mes_enable){
                 getUser();
-                // 查询工件质量
+                // 查询工件质量(常态停止定时器保持运行,待质量校验成功 UD 后再停)
                 Boolean sendret = DataUtil.checkQuality(nettyClient,scanBarcode,user20);
                 if(!sendret){
                     MesClient.setMenuStatus("消息发送失败,请重试",-1);
                     return;
                 }
-                // 扫码已通过本地校验并已发质量查询:此后不再发停止/复位
-                WorkTimer.stopStopTimer();
             }else{
                 work_status = 1;
                 MesClient.tjFlag = 1;
@@ -1085,6 +1164,18 @@ public class MesClient extends JFrame {
         f_start_bt.setFont(new Font("微软雅黑", Font.PLAIN, 28));
         f_start_bt.setBounds(756, 70, 120, 70);
         indexPanelA.add(f_start_bt);
+
+        f_retest_bt = new JButton("重测");
+        f_retest_bt.setEnabled(false);
+        f_retest_bt.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                retestLastSn();
+            }
+        });
+        f_retest_bt.setFont(new Font("微软雅黑", Font.PLAIN, 28));
+        f_retest_bt.setBounds(756, 148, 120, 70);
+        indexPanelA.add(f_retest_bt);
+        loadLastSubmittedSn();
         
         JLabel lblNewLabel = new JLabel("测试压");
         lblNewLabel.setFont(new Font("微软雅黑", Font.PLAIN, 20));

+ 2 - 0
src/com/mes/ui/MesRevice.java

@@ -17,6 +17,8 @@ public class MesRevice {
                 MesClient.check_quality_result = true;//质量合格,可以绑定加工
                 MesClient.work_status = 1;
                 MesClient.tjFlag = 1;
+                // 工件码质量校验成功:停止常态停止/复位定时器
+                WorkTimer.stopStopTimer();
                 MesClient.setMenuStatus("该工件可以测试,等待测试",0);
                 MesClient.product_sn.setEditable(false);
                 MesClient.loadAteqProgramTimes();

+ 130 - 10
src/com/mes/util/ATEQ.java

@@ -80,16 +80,99 @@ public class ATEQ {
     }
 
     /**
-     * 读取测试状态字 0x2204(1个字)
-     * 高字节: 00=测试中, 21=OK, 其他=各类NG
-     * 读法: 先 10 30 04 选程序,再 03 22 04
+     * 读取实时测试状态字 0x2204(完整 1 字)
+     * 手册: bit5=周期结束, bit0=pass(最终合格请用 Last Time 2303,勿单独用本寄存器定结果)
+     * 读法: 先 10 30 04 选程序,再 03 22 04 00 01
      */
     public static int readTestStatusCode() {
         byte[] read = selectThenReadHolding("22 04", 1);
-        if (read == null || read.length < 7) {
+        if (read == null || read.length < 5) {
             throw new RuntimeException("读取测试状态时, 返回的数据长度不够, hex=" + DataUtils.bytesToHex(read == null ? new byte[0] : read));
         }
-        return read[3] & 0xFF;
+        // 例: 应答 01 03 02 21 80 → 状态字 0x8021(小端)
+        return DataUtils.bytesToInt(Arrays.copyOfRange(read, 3, 5));
+    }
+
+    /**
+     * 读取 Last Time 最终测试状态 0x2303(ok/NG/alarm)
+     * 命令: 站号 03 23 03 00 01 + CRC;bit0=1 合格
+     */
+    public static int readLastTimeStatusWord() {
+        byte[] read = selectThenReadHolding("23 03", 1);
+        if (read == null || read.length < 5) {
+            throw new RuntimeException("读取最终状态2303失败, hex=" + DataUtils.bytesToHex(read == null ? new byte[0] : read));
+        }
+        int word = DataUtils.bytesToInt(Arrays.copyOfRange(read, 3, 5));
+        log.info("LastTime 2303 状态字=0x{}, bit0(合格)={}, 原始={}",
+                String.format("%04X", word), DataUtils.getBit(word, 0), DataUtils.bytesToHex(read));
+        return word;
+    }
+
+    /** Last Time 压力 2305-2306 */
+    public static double readLastTimePressure() {
+        return parseDwordValue(selectThenReadHolding("23 05", 2));
+    }
+
+    /** Last Time 压力单位 2307-2308 */
+    public static String readLastTimePressureUnit() {
+        return parseUnit(selectThenReadHolding("23 07", 2));
+    }
+
+    /** Last Time 泄漏 2309-230A */
+    public static double readLastTimeLeak() {
+        return parseDwordValue(selectThenReadHolding("23 09", 2));
+    }
+
+    /** Last Time 泄漏单位 230B-230C */
+    public static String readLastTimeLeakUnit() {
+        return parseUnit(selectThenReadHolding("23 0B", 2));
+    }
+
+    /**
+     * 测完后读取 Last Time 最终结果(2303 判 OK/NG,2305/2309 压力泄漏)
+     */
+    public static FinalResult readLastTimeFinalResult() {
+        int statusWord = 0;
+        boolean isPass = false;
+        double pressureValue = 0;
+        String pressureUnit = "";
+        double leakValue = 0;
+        String leakUnit = "";
+
+        try {
+            statusWord = readLastTimeStatusWord();
+            isPass = DataUtils.getBit(statusWord, 0) == 1;
+        } catch (Exception e) {
+            log.error("读最终状态2303失败: {}", e.getMessage());
+        }
+        sleepQuiet(50);
+        try {
+            pressureValue = readLastTimePressure();
+        } catch (Exception e) {
+            log.error("读最终压力2305失败: {}", e.getMessage());
+        }
+        sleepQuiet(50);
+        try {
+            pressureUnit = readLastTimePressureUnit();
+        } catch (Exception e) {
+            log.error("读最终压力单位2307失败: {}", e.getMessage());
+        }
+        sleepQuiet(50);
+        try {
+            leakValue = readLastTimeLeak();
+        } catch (Exception e) {
+            log.error("读最终泄漏2309失败: {}", e.getMessage());
+        }
+        sleepQuiet(50);
+        try {
+            leakUnit = readLastTimeLeakUnit();
+        } catch (Exception e) {
+            log.error("读最终泄漏单位230B失败: {}", e.getMessage());
+        }
+
+        FinalResult finalResult = new FinalResult(statusWord, isPass, pressureValue, pressureUnit, leakValue, leakUnit);
+        log.info(finalResult.toString());
+        return finalResult;
     }
 
     /** 压力 0x2206:先 10 30 04,再 03 22 06 00 02 */
@@ -237,12 +320,17 @@ public class ATEQ {
     }
 
     public static class MeasureResult {
-        public final int statusCode;       // 状态高字节: 00测试中, 21=OK, 其他=NG
+        /** 2204 完整状态字(如 0x8021) */
+        public final int statusCode;
         public final Double pressureValue;
         public final String pressureUnit;
         public final Double leakValue;
         public final String leakUnit;
+        /** bit5=0:测试进行中 */
         public final boolean isTesting;
+        /** bit5=1:周期结束(最终 OK/NG 请读 2303) */
+        public final boolean isCycleEnd;
+        /** 2204 的 bit0,仅参考,收尾以 FinalResult 为准 */
         public final boolean isPass;
 
         public MeasureResult(int statusCode, Double pressureValue, String pressureUnit,
@@ -252,22 +340,54 @@ public class ATEQ {
             this.pressureUnit = pressureUnit != null ? pressureUnit : "";
             this.leakValue = leakValue;
             this.leakUnit = leakUnit != null ? leakUnit : "";
-            this.isTesting = statusCode == 0x00;
-            this.isPass = statusCode == 0x21;
+            this.isCycleEnd = DataUtils.getBit(statusCode, 5) == 1;
+            this.isTesting = !this.isCycleEnd;
+            this.isPass = DataUtils.getBit(statusCode, 0) == 1;
         }
 
         @Override
         public String toString() {
             return "测量结果{" +
-                    " 状态码: 0x" + String.format("%02X", statusCode) +
+                    " 状态字: 0x" + String.format("%04X", statusCode) +
                     ", 测试中: " + isTesting +
-                    ", 通过: " + isPass +
+                    ", 周期结束: " + isCycleEnd +
+                    ", bit0参考合格: " + isPass +
                     ", 压力值: " + pressureValue + pressureUnit +
                     ", 泄漏值: " + leakValue + leakUnit +
                     '}';
         }
     }
 
+    /** Last Time(23xx)最终结果 */
+    public static class FinalResult {
+        public final int statusWord;       // 2303
+        public final boolean isPass;       // bit0
+        public final Double pressureValue;
+        public final String pressureUnit;
+        public final Double leakValue;
+        public final String leakUnit;
+
+        public FinalResult(int statusWord, boolean isPass, Double pressureValue, String pressureUnit,
+                           Double leakValue, String leakUnit) {
+            this.statusWord = statusWord;
+            this.isPass = isPass;
+            this.pressureValue = pressureValue;
+            this.pressureUnit = pressureUnit != null ? pressureUnit : "";
+            this.leakValue = leakValue;
+            this.leakUnit = leakUnit != null ? leakUnit : "";
+        }
+
+        @Override
+        public String toString() {
+            return "最终结果LastTime{" +
+                    " 2303=0x" + String.format("%04X", statusWord) +
+                    ", 通过: " + isPass +
+                    ", 压力: " + pressureValue + pressureUnit +
+                    ", 泄漏: " + leakValue + leakUnit +
+                    '}';
+        }
+    }
+
     // 读取实时结果(旧协议,保留备用)
     public static RealtimeResult readRealtimeResult() {
         String s1 = DataUtils.CRC16(ATEQ.getStationNo()+" 03 00 30 00 0D");

+ 1 - 0
src/com/mes/util/SerialPortUtils.java

@@ -167,6 +167,7 @@ public class SerialPortUtils {
                                                         String testDate = DateLocalUtils.getCurrentTime();
                                                         testParam.setCreateTime(testDate);
                                                         JdbcUtils.insertTestRecord(testParam);
+                                                        MesClient.saveLastSubmittedSn(testParam.getSn());
 
                                                         if(MesClient.mes_enable){ // MES开启
                                                             JSONObject retObj = DataUtil.qmResultData(testParam);

+ 55 - 12
src/com/mes/util/WorkTimer.java

@@ -81,14 +81,23 @@ public class WorkTimer {
                     log.info(measureResult.toString());
 
                     // 测完提交前:若稳压/测试时长为空,再读一次程序参数
-                    boolean willEnd = !measureResult.isTesting && MesClient.mesStartFlag == 1;
+                    boolean willEnd = measureResult.isCycleEnd && MesClient.mesStartFlag == 1;
+                    ATEQ.FinalResult finalResult = null;
                     if (willEnd) {
+                        log.info("2204周期结束 status=0x{}, bit5=1, bit0参考={}, 开始读LastTime 2303",
+                                String.format("%04X", measureResult.statusCode), measureResult.isPass);
+                        try {
+                            finalResult = ATEQ.readLastTimeFinalResult();
+                        } catch (Exception e) {
+                            log.error("读LastTime最终结果失败: {}", e.getMessage());
+                        }
                         if ((MesClient.curStabilizeTime == null || MesClient.curStabilizeTime.trim().isEmpty())
                                 || (MesClient.curTestDuration == null || MesClient.curTestDuration.trim().isEmpty())) {
                             log.info("提交前补读稳压时长/测试时长");
                             MesClient.loadAteqProgramTimes();
                         }
                     }
+                    final ATEQ.FinalResult endResult = finalResult;
 
                     SwingUtilities.invokeLater(new Runnable() {
                         @Override
@@ -98,25 +107,57 @@ public class WorkTimer {
                                 if (measureResult.isTesting) {
                                     MesClient.mesStartFlag = 1;
                                     MesClient.setStartButtonEnabled(false);
+                                    MesClient.refreshRetestButton();
                                     MesClient.setMenuStatus("测试中", 0);
-                                } else if (MesClient.mesStartFlag == 1) {
-                                    // 曾进入测试中,状态变为非00,表示测试结束
+                                } else if (MesClient.mesStartFlag == 1 && measureResult.isCycleEnd) {
+                                    // bit5=1:周期结束,用 2303 最终判定
                                     isEnd = true;
                                 }
 
-                                String pressureText = formatValue(measureResult.pressureValue, measureResult.pressureUnit);
-                                String leakText = formatValue(measureResult.leakValue, measureResult.leakUnit);
+                                Double pressureVal = measureResult.pressureValue;
+                                String pressureUnit = measureResult.pressureUnit;
+                                Double leakVal = measureResult.leakValue;
+                                String leakUnit = measureResult.leakUnit;
+                                boolean isPass = measureResult.isPass;
+
+                                if (isEnd) {
+                                    if (endResult != null) {
+                                        isPass = endResult.isPass;
+                                        if (endResult.pressureValue != null) {
+                                            pressureVal = endResult.pressureValue;
+                                        }
+                                        if (endResult.pressureUnit != null && !endResult.pressureUnit.isEmpty()) {
+                                            pressureUnit = endResult.pressureUnit;
+                                        }
+                                        if (endResult.leakValue != null) {
+                                            leakVal = endResult.leakValue;
+                                        }
+                                        if (endResult.leakUnit != null && !endResult.leakUnit.isEmpty()) {
+                                            leakUnit = endResult.leakUnit;
+                                        }
+                                        log.info("最终判定: 2204=0x{}, 2303=0x{}, OK/NG={}",
+                                                String.format("%04X", measureResult.statusCode),
+                                                String.format("%04X", endResult.statusWord),
+                                                isPass ? "OK" : "NG");
+                                    } else {
+                                        isPass = false;
+                                        log.error("未读到2303最终状态,按NG处理");
+                                    }
+                                }
+
+                                String pressureText = formatValue(pressureVal, pressureUnit);
+                                String leakText = formatValue(leakVal, leakUnit);
 
                                 // 实时更新显示(不因单项失败而整页空白)
                                 MesClient.param1.setText(pressureText);
                                 MesClient.param2.setText(leakText);
 
                                 if (isEnd) {
-                                    if (measureResult.leakValue == 0 && !measureResult.isPass) {
+                                    if (leakVal != null && leakVal == 0 && !isPass) {
                                         MesClient.param2.setText("9999");
                                     }
 
-                                    String lastRet = measureResult.isPass ? "OK" : "NG";
+                                    String lastRet = isPass ? "OK" : "NG";
 
                                     if (lastRet.equals("OK")) {
                                         MesClient.result.setText("OK");
@@ -134,10 +175,10 @@ public class WorkTimer {
                                     testParam.setLineSn(MesClient.configParam.getLineSn());
                                     testParam.setOprno(MesClient.configParam.getOprno());
                                     testParam.setOprnoTitle(MesClient.configParam.getOprnoTitle());
-                                    testParam.setParam1(measureResult.pressureValue + "");
-                                    testParam.setParam2(measureResult.pressureUnit);
-                                    testParam.setParam3(measureResult.leakValue + "");
-                                    testParam.setParam4(measureResult.leakUnit);
+                                    testParam.setParam1(pressureVal + "");
+                                    testParam.setParam2(pressureUnit);
+                                    testParam.setParam3(leakVal + "");
+                                    testParam.setParam4(leakUnit);
                                     testParam.setParam5(MesClient.programNo.getText().trim());
                                     testParam.setResult(lastRet);
                                     testParam.setDeviceType("ateq");
@@ -147,9 +188,11 @@ public class WorkTimer {
                                     testParam.setStabilizeTime(byVal);
                                     testParam.setTestDuration(csVal);
                                     log.info("准备提交时长: by(稳压时长)={}, cs(测试时长)={}", byVal, csVal);
-                                    testParam.setRemark(measureResult.isPass ? "" : String.format("状态码:0x%02X", measureResult.statusCode));
+                                    int remarkStatus = endResult != null ? endResult.statusWord : measureResult.statusCode;
+                                    testParam.setRemark(isPass ? "" : String.format("状态字:0x%04X", remarkStatus));
                                     testParam.setCreateTime(testDate);
                                     JdbcUtils.insertTestRecord(testParam);
+                                    MesClient.saveLastSubmittedSn(testParam.getSn());
 
                                     if (MesClient.mes_enable) { // MES开启
                                         JSONObject retObj = DataUtil.qmResultData(testParam);