3 Ревизии 0cafc54cf1 ... abb2400694

Автор SHA1 Съобщение Дата
  张田野 abb2400694 Merge remote-tracking branch 'origin/master' преди 2 седмици
  张田野 ee0a56b41b 判定气密的范围改为mes写死 преди 2 седмици
  hzd 3ad92faa48 inno преди 3 месеца
променени са 2 файла, в които са добавени 310 реда и са изтрити 166 реда
  1. 218 57
      src/com/mes/util/ytnetty/QmResultUtil.java
  2. 92 109
      src/com/mes/util/ytnetty/YtNettyClientHandler.java

+ 218 - 57
src/com/mes/util/ytnetty/QmResultUtil.java

@@ -1,85 +1,217 @@
 package com.mes.util.ytnetty;
 
-import com.mes.util.DataUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Arrays;
-
+/**
+ * 最终结果 4353 / CS。
+ * 旧实现按 hex 下标截取,字段一错位 OK/NG、压强、泄漏全歪;
+ * 现先 hex→ASCII,再按定长或 CSV 解析。
+ */
 public class QmResultUtil {
-    public static final Logger log =  LoggerFactory.getLogger(QmResultUtil.class);
-
-    public final String num; // 记录编号
-    public final String testDate; // 记录编号
-    public final String sn; // 工件号
-    public final String resultType; // 结果符号
-    public final String result; // 结果
-    public final String programNumber;               // 程序号
-    public final String pressureValue;                // 压力值
-    public final String leakValue;                    // 泄漏值
-    public final String pressureUnit;                 // 压力单位
-    public final String leakUnit;                     // 泄漏单位
+    public static final Logger log = LoggerFactory.getLogger(QmResultUtil.class);
+
+    public final String num;
+    public final String testDate;
+    public final String sn;
+    public final String resultType;
+    public final String result;
+    public final String programNumber;
+    public final String pressureValue;
+    public final String leakValue;
+    public final String pressureUnit;
+    public final String leakUnit;
 
     public QmResultUtil(String msg) {
-        this.num = new String(YtUtil.hexStringToByteArray(msg.substring(4,14)));
-        this.testDate = new String(YtUtil.hexStringToByteArray(msg.substring(14,42)));
-        this.sn = new String(YtUtil.hexStringToByteArray(msg.substring(48,108)));
-        this.resultType = new String(YtUtil.hexStringToByteArray(msg.substring(108,110)));
-        String leak = Double.valueOf(new String(YtUtil.hexStringToByteArray(msg.substring(110,122))))+"";
-        this.leakUnit = formatLeakUnit(new String(YtUtil.hexStringToByteArray(msg.substring(122,124))));
-        this.result = formatResult(new String(YtUtil.hexStringToByteArray(msg.substring(124,126))));
-        this.programNumber = new String(YtUtil.hexStringToByteArray(msg.substring(126,130)));
-        this.pressureValue = Double.valueOf(new String(YtUtil.hexStringToByteArray(msg.substring(130,146))))+"";
-        this.pressureUnit = "kpa";
-        if(this.resultType.equals("1")){
-             leak = "-"+leak;
-        }
-        this.leakValue = leak;
+        String ascii = new String(YtUtil.hexStringToByteArray(msg));
+        log.info("QmResultUtil ascii={}", ascii);
+
+        if (ascii.indexOf(',') >= 0) {
+            Parsed p = parseCsv(ascii);
+            this.num = p.num;
+            this.testDate = p.testDate;
+            this.sn = p.sn;
+            this.resultType = p.resultType;
+            this.result = p.result;
+            this.programNumber = p.programNumber;
+            this.pressureValue = p.pressureValue;
+            this.leakValue = p.leakValue;
+            this.pressureUnit = p.pressureUnit;
+            this.leakUnit = p.leakUnit;
+            return;
+        }
+
+        Parsed p = parseFixed(ascii);
+        this.num = p.num;
+        this.testDate = p.testDate;
+        this.sn = p.sn;
+        this.resultType = p.resultType;
+        this.result = p.result;
+        this.programNumber = p.programNumber;
+        this.pressureValue = p.pressureValue;
+        this.leakValue = p.leakValue;
+        this.pressureUnit = p.pressureUnit;
+        this.leakUnit = p.leakUnit;
     }
 
-    @Override
-    public String toString() {
-        return "QmResultUtil{" +
-                "num='" + num + '\'' +
-                ", testDate='" + testDate + '\'' +
-                ", sn='" + sn + '\'' +
-                ", resultType='" + resultType + '\'' +
-                ", result='" + result + '\'' +
-                ", programNumber='" + programNumber + '\'' +
-                ", pressureValue='" + pressureValue + '\'' +
-                ", leakValue='" + leakValue + '\'' +
-                ", pressureUnit='" + pressureUnit + '\'' +
-                ", leakUnit='" + leakUnit + '\'' +
-                '}';
+    /**
+     * 定长:CS + num(5) + date(14) + reserved(3) + sn(30)
+     * + resultType(1) + leak(6) + leakUnit(1) + result(1) + program(2) + pressure(8)
+     * 例:CS0035620260706160102000...(sn)...0001.55310002013.2800 → result='1'=OK
+     */
+    private Parsed parseFixed(String ascii) {
+        Parsed p = new Parsed();
+        if (ascii == null || ascii.length() < 73) {
+            log.warn("CS定长包过短 len={}", ascii == null ? 0 : ascii.length());
+            p.result = "NG";
+            p.pressureUnit = "kPa";
+            return p;
+        }
+
+        p.num = safeSub(ascii, 2, 7).trim();
+        p.testDate = safeSub(ascii, 7, 21).trim();
+        p.sn = safeSub(ascii, 24, 54).trim();
+        p.resultType = safeSub(ascii, 54, 55);
+        String leakRaw = safeSub(ascii, 55, 61).trim();
+        p.leakUnit = formatLeakUnit(safeSub(ascii, 61, 62));
+        p.result = formatResult(safeSub(ascii, 62, 63));
+        p.programNumber = safeSub(ascii, 63, 65).trim();
+        p.pressureValue = toNumberString(safeSub(ascii, 65, 73));
+        p.pressureUnit = "kPa";
+
+        String leak = toNumberString(leakRaw);
+        if ("1".equals(p.resultType) && leak.length() > 0 && !leak.startsWith("-")) {
+            leak = "-" + leak;
+        }
+        p.leakValue = leak;
+        return p;
+    }
+
+    /**
+     * CSV:与实时 RS 一样整包为逗号分隔。
+     * 优先识别字面 OK/NG;否则按 CS,num,date,sn,resultType,leak,unit,result,program,pressure 取值。
+     */
+    private Parsed parseCsv(String ascii) {
+        Parsed p = new Parsed();
+        String[] parts = ascii.split(",", -1);
+        p.pressureUnit = "kPa";
+
+        for (String part : parts) {
+            if (part == null) {
+                continue;
+            }
+            String t = part.trim();
+            if ("OK".equalsIgnoreCase(t) || "NG".equalsIgnoreCase(t)) {
+                p.result = t.toUpperCase();
+                break;
+            }
+        }
+
+        p.num = part(parts, 1);
+        p.testDate = part(parts, 2);
+        p.sn = part(parts, 3);
+        p.resultType = part(parts, 4);
+        if (p.leakValue == null || p.leakValue.isEmpty()) {
+            p.leakValue = toNumberString(part(parts, 5));
+        }
+        String unitCode = part(parts, 6);
+        p.leakUnit = formatLeakUnit(unitCode);
+        if (p.result == null || p.result.isEmpty()) {
+            p.result = formatResult(part(parts, 7));
+        }
+        p.programNumber = part(parts, 8);
+        p.pressureValue = toNumberString(part(parts, 9));
+        // 若压力在更前(类似 RS: 第5/6 段是压强/泄漏)
+        if (p.pressureValue.isEmpty() && parts.length >= 6) {
+            String maybePressure = toNumberString(part(parts, 4));
+            String maybeLeak = toNumberString(part(parts, 5));
+            if (!maybePressure.isEmpty()) {
+                p.pressureValue = maybePressure;
+            }
+            if (!maybeLeak.isEmpty()) {
+                p.leakValue = maybeLeak;
+            }
+        }
+        if ("1".equals(p.resultType) && p.leakValue.length() > 0 && !p.leakValue.startsWith("-")) {
+            p.leakValue = "-" + p.leakValue;
+        }
+        if (p.result == null || p.result.isEmpty()) {
+            p.result = "NG";
+        }
+        return p;
+    }
+
+    private static String part(String[] parts, int index) {
+        if (parts == null || index < 0 || index >= parts.length || parts[index] == null) {
+            return "";
+        }
+        return parts[index].trim();
+    }
+
+    private static String safeSub(String s, int start, int end) {
+        if (s == null || start >= s.length()) {
+            return "";
+        }
+        if (end > s.length()) {
+            end = s.length();
+        }
+        if (start < 0) {
+            start = 0;
+        }
+        if (start >= end) {
+            return "";
+        }
+        return s.substring(start, end);
+    }
+
+    private static String toNumberString(String raw) {
+        if (raw == null) {
+            return "";
+        }
+        String t = raw.trim();
+        if (t.isEmpty()) {
+            return "";
+        }
+        try {
+            return Double.valueOf(t) + "";
+        } catch (Exception e) {
+            return t;
+        }
     }
 
     public String formatLeakUnit(String leakUnit) {
-        String unit = "";
-        switch (leakUnit) {
+        if (leakUnit == null) {
+            return "";
+        }
+        switch (leakUnit.trim()) {
             case "0":
-                unit = "P";
-                break;
+                return "P";
             case "1":
-                unit = "Pa/s";
-                break;
+                return "Pa/s";
             case "2":
-                unit = "mL/s";
-                break;
+                return "mL/s";
             case "3":
-                unit = "mL/min";
-                break;
+                return "mL/min";
             case "4":
-                unit = "cc/min";
-                break;
+                return "cc/min";
+            default:
+                // 已是单位文本则原样返回
+                if (leakUnit.contains("Pa") || leakUnit.contains("mL") || leakUnit.contains("cc") || "P".equals(leakUnit.trim())) {
+                    return leakUnit.trim();
+                }
+                return "";
         }
-        return unit;
     }
 
     public String formatResult(String result) {
         if (result == null || result.trim().isEmpty()) {
             return "NG";
         }
-        switch (result.trim()) {
+        String r = result.trim();
+        if ("OK".equalsIgnoreCase(r) || "NG".equalsIgnoreCase(r)) {
+            return r.toUpperCase();
+        }
+        switch (r) {
             case "1":
                 return "OK";
             case "2": // +NG
@@ -94,4 +226,33 @@ public class QmResultUtil {
                 return "NG";
         }
     }
+
+    @Override
+    public String toString() {
+        return "QmResultUtil{" +
+                "num='" + num + '\'' +
+                ", testDate='" + testDate + '\'' +
+                ", sn='" + sn + '\'' +
+                ", resultType='" + resultType + '\'' +
+                ", result='" + result + '\'' +
+                ", programNumber='" + programNumber + '\'' +
+                ", pressureValue='" + pressureValue + '\'' +
+                ", leakValue='" + leakValue + '\'' +
+                ", pressureUnit='" + pressureUnit + '\'' +
+                ", leakUnit='" + leakUnit + '\'' +
+                '}';
+    }
+
+    private static class Parsed {
+        String num = "";
+        String testDate = "";
+        String sn = "";
+        String resultType = "";
+        String result = "";
+        String programNumber = "";
+        String pressureValue = "";
+        String leakValue = "";
+        String pressureUnit = "";
+        String leakUnit = "";
+    }
 }

+ 92 - 109
src/com/mes/util/ytnetty/YtNettyClientHandler.java

@@ -16,21 +16,21 @@ import java.util.Date;
 
 public class YtNettyClientHandler extends ChannelInboundHandlerAdapter {
 
-    public static final Logger log =  LoggerFactory.getLogger(YtNettyClientHandler.class);
+    public static final Logger log = LoggerFactory.getLogger(YtNettyClientHandler.class);
+
+    /** 泄露值合格区间(含边界) */
+    private static final double LEAK_OK_MIN = -4.0;
+    private static final double LEAK_OK_MAX = 8.0;
 
     private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     public static byte[] responseByte;
 
-    //当前超时次数
     private int timeoutNum = 0;
-
-    //运行最大超时次数
     private int timeoutNumMax = 3;
 
     @Override
     public void channelActive(ChannelHandlerContext ctx) throws Exception {
         log.info("mes connecting:" + sdf.format(new Date()));
-//        YtNettyClient.tcpOnline = 1;
     }
 
     @Override
@@ -44,7 +44,6 @@ public class YtNettyClientHandler extends ChannelInboundHandlerAdapter {
         YtNettyClient.doConnect();
     }
 
-    //读写超时发送心跳
     @Override
     public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
         IdleState state = ((IdleStateEvent) evt).state();
@@ -56,8 +55,7 @@ public class YtNettyClientHandler extends ChannelInboundHandlerAdapter {
                 ctx.channel().close();
             }
         }
-        if(state.equals(IdleState.ALL_IDLE)){
-            //给服务端端发送心跳请求
+        if (state.equals(IdleState.ALL_IDLE)) {
             sendHeartbeatPacket(ctx);
         }
     }
@@ -65,141 +63,126 @@ public class YtNettyClientHandler extends ChannelInboundHandlerAdapter {
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {
         timeoutNum = 0;
-        log.info("message:"+message);
-        String msg = message+"";
+        log.info("message:" + message);
+        String msg = message + "";
         String code = YtUtil.getCode(msg);
-        log.info("code:"+code);
-        log.info("msg:"+msg);
-        try{
-            switch (code){
-                case "4353": // 测试结果
-                    // 未扫码、未进入本轮测试、工件码为空、或本轮已入库时,忽略旧结果/重复结果
-                    if(MesClient.work_status != 1){
-                        log.info("忽略测试结果:未扫码,work_status={}", MesClient.work_status);
-                        break;
-                    }
-                    if(MesClient.mesStartFlag != 1){
-                        log.info("忽略测试结果:本轮测试尚未开始(未检测到充气等中间步骤),可能是上一件旧结果");
-                        break;
-                    }
-                    if(MesClient.mesTjFlag != 0){
-                        log.info("忽略测试结果:本轮结果已处理,mesTjFlag={}", MesClient.mesTjFlag);
-                        break;
-                    }
-                    String sn = MesClient.product_sn.getText().trim();
-                    if(sn.isEmpty()){
-                        log.info("忽略测试结果:工件码为空");
-                        break;
-                    }
-                    // 先占位,防止同一轮重复入库
-                    MesClient.mesTjFlag = 1;
-
-                    QmResultUtil qmResultUtil = new QmResultUtil(msg);
-                    log.info("qmResultUtil:"+qmResultUtil.toString());
-                    // 压强/泄漏数值优先用本轮 RS(与气密仪一致);单位仍取 4353(RS 无单位字段)
-                    boolean useCur = MesClient.lastQmPressure != null && !MesClient.lastQmPressure.trim().isEmpty();
-                    String pressureValue = useCur ? MesClient.lastQmPressure.trim() : qmResultUtil.pressureValue;
-                    String leakValue = useCur && MesClient.lastQmLeak != null
-                            ? MesClient.lastQmLeak.trim() : qmResultUtil.leakValue;
-                    String pressureUnit = qmResultUtil.pressureUnit != null && !qmResultUtil.pressureUnit.trim().isEmpty()
-                            ? qmResultUtil.pressureUnit.trim() : "kPa";
-                    String leakUnit = qmResultUtil.leakUnit != null ? qmResultUtil.leakUnit.trim() : "";
-                    if(useCur){
-                        log.info("提交采用实时RS值 pressure={}{}, leak={}{}", pressureValue, pressureUnit, leakValue, leakUnit);
-                    }
-                    MesClient.param1.setText(pressureValue + pressureUnit);
-                    MesClient.param2.setText(leakValue + leakUnit);
-                    String lastRet = "OK".equals(qmResultUtil.result) ? "OK" : "NG";
-                    if(lastRet.equals("OK")){
-                        MesClient.result.setText("OK");
-                        MesClient.result.setForeground(Color.GREEN);
-                    }else{
-                        MesClient.result.setText("NG");
-                        MesClient.result.setForeground(Color.RED);
-                    }
-                    TestParam testParam = new TestParam();
-                    testParam.setSn(sn);
-                    testParam.setParam1(pressureValue);
-                    testParam.setParam2(pressureUnit);
-                    testParam.setParam3(leakValue);
-                    testParam.setParam4(leakUnit);
-                    testParam.setResult(lastRet);
-                    if(lastRet.equals("NG")){
-                        testParam.setRemark(qmResultUtil.result);
-                    }else{
-                        testParam.setRemark("");
-                    }
-                    MesClient.fillMesTestMeta(testParam);
-                    MesClient.afterTestSaveAndUpload(testParam);
-
+        log.info("code:" + code);
+        log.info("msg:" + msg);
+        try {
+            switch (code) {
+                case "4353": // 不再用气密仪自带OK/NG;判定改由结束时的泄露值区间
+                    log.info("忽略4353设备判定结果,OK/NG由泄露值区间判定");
                     break;
                 case "5253": // 实时结果
-                    // 未扫码时不处理实时流程,避免设备自行测试触发读结果并入库
-                    if(MesClient.work_status != 1){
+                    if (MesClient.work_status != 1) {
                         break;
                     }
                     QmCurUtil qmCurUtil = new QmCurUtil(msg);
-                    log.info("qmCurUtil:"+qmCurUtil.toString());
-                    // 仅中间步骤开启本轮;65535 等结束态不能开轮,否则扫新码会立刻读旧结果并提交
-                    if(qmCurUtil.isRunningStep()){
-                        if(MesClient.mesStartFlag == 0 || MesClient.mesTjFlag == 1){
+                    log.info("qmCurUtil:" + qmCurUtil.toString());
+                    // 仅中间步骤开启本轮
+                    if (qmCurUtil.isRunningStep()) {
+                        if (MesClient.mesStartFlag == 0 || MesClient.mesTjFlag == 1) {
                             MesClient.mesStartFlag = 1;
                             MesClient.mesTjFlag = 0;
                             log.info("本轮测试已开始,step={}", qmCurUtil.step);
                         }
+                        // 测试中不显示OK/NG
+                        if (MesClient.result != null
+                                && !"等待结果".equals(MesClient.result.getText())) {
+                            MesClient.result.setText("等待结果");
+                            MesClient.result.setForeground(Color.GRAY);
+                        }
                     }
-                    MesClient.setMenuStatus("当前步骤:"+qmCurUtil.step, 0); // 当前步骤
-                    // 实时更新显示的压力值和泄漏值(与气密仪一致)
+                    MesClient.setMenuStatus("当前步骤:" + qmCurUtil.step, 0);
+                    // 实时只刷压强/泄漏数值,不刷OK/NG
                     MesClient.param1.setText(qmCurUtil.pressureValue);
                     MesClient.param2.setText(qmCurUtil.leakValue);
-                    if(qmCurUtil.pressureValue != null && !qmCurUtil.pressureValue.trim().isEmpty()){
+                    if (qmCurUtil.pressureValue != null && !qmCurUtil.pressureValue.trim().isEmpty()) {
                         MesClient.lastQmPressure = qmCurUtil.pressureValue.trim();
                     }
-                    if(qmCurUtil.leakValue != null && !qmCurUtil.leakValue.trim().isEmpty()){
+                    if (qmCurUtil.leakValue != null && !qmCurUtil.leakValue.trim().isEmpty()) {
                         MesClient.lastQmLeak = qmCurUtil.leakValue.trim();
                     }
 
-                    // 读最终结果:必须本轮已由中间步开启(mesStartFlag=1)后,再遇到结束步才请求 4353
-                    if(MesClient.mesStartFlag == 1 && MesClient.mesTjFlag == 0){
-                        if(qmCurUtil.isEndStep()){
-                            log.info("读取测试结果,当前step={}, pressure={}, leak={}",
-                                    qmCurUtil.step, MesClient.lastQmPressure, MesClient.lastQmLeak);
-                            ctx.writeAndFlush(YtUtil.getSendByteBuf(YtUtil.getResultCommon()));
-                        }
+                    // 气密仪结束步:才判定并显示OK/NG、提交
+                    if (MesClient.mesStartFlag == 1 && MesClient.mesTjFlag == 0 && qmCurUtil.isEndStep()) {
+                        finishByLeakRange();
                     }
-
                     break;
-                case "5453": // 设备状态
-
-                    break;
-                case "4F4B": // 指令执行成功
-
-                    break;
-                case "4552": // 非法操作或校验位错误
-
+                case "5453":
+                case "4F4B":
+                case "4552":
                     break;
             }
-        }catch (Exception e){
+        } catch (Exception e) {
             e.printStackTrace();
         }
+    }
 
+    /**
+     * 测试结束:按泄露值 [-4, 8] 判定 OK/NG,显示并提交。
+     * 不再使用气密仪 4353 自带判定结果。
+     */
+    private void finishByLeakRange() {
+        String sn = MesClient.product_sn.getText().trim();
+        if (sn.isEmpty()) {
+            log.info("结束判定跳过:工件码为空");
+            return;
+        }
+        String pressureValue = MesClient.lastQmPressure != null ? MesClient.lastQmPressure.trim() : "";
+        String leakValue = MesClient.lastQmLeak != null ? MesClient.lastQmLeak.trim() : "";
+        if (leakValue.isEmpty()) {
+            log.info("结束判定跳过:泄露值尚未收到");
+            return;
+        }
 
+        MesClient.mesTjFlag = 1;
+
+        boolean ok = isLeakOk(leakValue);
+        String lastRet = ok ? "OK" : "NG";
+        log.info("测试结束判定:leak={}, 区间[{}, {}], result={}",
+                leakValue, LEAK_OK_MIN, LEAK_OK_MAX, lastRet);
+
+        String pressureUnit = "kPa";
+        MesClient.param1.setText(pressureValue + pressureUnit);
+        MesClient.param2.setText(leakValue);
+        if (ok) {
+            MesClient.result.setText("OK");
+            MesClient.result.setForeground(Color.GREEN);
+        } else {
+            MesClient.result.setText("NG");
+            MesClient.result.setForeground(Color.RED);
+        }
+
+        TestParam testParam = new TestParam();
+        testParam.setSn(sn);
+        testParam.setParam1(pressureValue);
+        testParam.setParam2(pressureUnit);
+        testParam.setParam3(leakValue);
+        testParam.setParam4("");
+        testParam.setResult(lastRet);
+        testParam.setRemark(ok ? "" : "泄露值超限(" + LEAK_OK_MIN + "~" + LEAK_OK_MAX + ")");
+        MesClient.fillMesTestMeta(testParam);
+        MesClient.afterTestSaveAndUpload(testParam);
+    }
+
+    /** 泄露值在 [-4, 8](含边界)为 OK,否则 NG */
+    static boolean isLeakOk(String leakValue) {
+        try {
+            double v = Double.parseDouble(leakValue.trim());
+            return v >= LEAK_OK_MIN && v <= LEAK_OK_MAX;
+        } catch (Exception e) {
+            log.warn("泄露值无法解析为数字: {}", leakValue);
+            return false;
+        }
     }
 
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
         System.out.println("exceptionCaught");
-//        ctx.close();
     }
 
-    /**
-     * 发送心跳包
-     *
-     * @param ctx
-     */
     private void sendHeartbeatPacket(ChannelHandlerContext ctx) {
-        // 查询状态当做心跳
         ctx.writeAndFlush(YtUtil.getSendByteBuf(YtUtil.getStateCommon()));
     }
-
 }