package com.mes.util.ytnetty; import com.mes.ui.MesClient; import com.mes.util.DateLocalUtils; import com.mes.util.TestParam; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.timeout.IdleState; import io.netty.handler.timeout.IdleStateEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; import java.text.SimpleDateFormat; import java.util.Date; public class YtNettyClientHandler extends ChannelInboundHandlerAdapter { public static final Logger log = LoggerFactory.getLogger(YtNettyClientHandler.class); /** 泄露值合格区间(含边界) */ private static final double LEAK_OK_MIN = -10.0; private static final double LEAK_OK_MAX = 2.5; 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())); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); log.error("close tcp, ip:" + channel.remoteAddress()); YtNettyClient.tcpOnline = 0; System.out.println("3s 之后尝试重新连接服务器..."); Thread.sleep(3 * 1000); YtNettyClient.doConnect(); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { IdleState state = ((IdleStateEvent) evt).state(); if (state.equals(IdleState.READER_IDLE)) { System.out.println("客户端read超时" + (timeoutNum++) + "次"); if (timeoutNum > timeoutNumMax) { System.out.println("超时次数上限,关闭这个不活跃的连接"); ctx.channel().close(); } } if (state.equals(IdleState.ALL_IDLE)) { sendHeartbeatPacket(ctx); } } @Override public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception { timeoutNum = 0; log.info("message:" + message); String msg = message + ""; String code = YtUtil.getCode(msg); log.info("code:" + code); log.info("msg:" + msg); try { if (MesClient.configParam != null && !isInntaiDevice(MesClient.configParam.getDevice())) { return; } switch (code) { case "4353": // 最终结果 CS if (MesClient.work_status != 1 || MesClient.mesTjFlag == 1) { log.info("忽略4353:未在测试中或本轮已提交"); break; } MesClient.mesTjFlag = 1; String sn = MesClient.product_sn.getText().trim(); QmResultUtil qmResultUtil = new QmResultUtil(msg); log.info("INNTAI最终结果 {}", qmResultUtil); MesClient.param1.setText(qmResultUtil.pressureValue); MesClient.param2.setText(qmResultUtil.leakValue); if ("OK".equals(qmResultUtil.result)) { 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.setOprno(MesClient.getEffectiveOprno()); testParam.setOprnoTitle(MesClient.configParam != null ? MesClient.configParam.getOprnoTitle() : ""); testParam.setLineSn(MesClient.getEffectiveLineSn()); testParam.setUcode(MesClient.user_menu != null ? MesClient.user_menu.getText().trim() : ""); testParam.setParam1(qmResultUtil.pressureValue); testParam.setParam2(qmResultUtil.pressureUnit); testParam.setParam3(qmResultUtil.leakValue); testParam.setParam4(qmResultUtil.leakUnit); testParam.setParam5(MesClient.configParam != null && MesClient.configParam.getProgramNo() != null ? MesClient.configParam.getProgramNo() : ""); testParam.setResult(qmResultUtil.result); testParam.setDeviceType(MesClient.configParam != null ? MesClient.configParam.getDevice() : "INNTAI"); testParam.setRemark(""); testParam.setCreateTime(DateLocalUtils.getCurrentTime()); MesClient.afterTestSaveAndUpload(testParam); break; case "5253": // 实时结果 if (MesClient.work_status != 1 || MesClient.workstop == 1) { break; } QmCurUtil qmCurUtil = new QmCurUtil(msg); 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); // 实时只刷压强/泄漏数值,不刷OK/NG MesClient.param1.setText(qmCurUtil.pressureValue); MesClient.param2.setText(qmCurUtil.leakValue); if (qmCurUtil.pressureValue != null && !qmCurUtil.pressureValue.trim().isEmpty()) { MesClient.lastQmPressure = qmCurUtil.pressureValue.trim(); } if (qmCurUtil.leakValue != null && !qmCurUtil.leakValue.trim().isEmpty()) { MesClient.lastQmLeak = qmCurUtil.leakValue.trim(); } // 气密仪结束步:才判定并显示OK/NG、提交 if (MesClient.mesStartFlag == 1 && MesClient.mesTjFlag == 0 && qmCurUtil.isEndStep()) { // finishByLeakRange(); MesClient.workstop = 1; ctx.writeAndFlush(YtUtil.getSendByteBuf(YtUtil.getResultCommon())); } break; case "5453": case "4F4B": case "4552": break; } } 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 + ")"); testParam.setOprno(MesClient.getEffectiveOprno()); testParam.setOprnoTitle(MesClient.configParam != null ? MesClient.configParam.getOprnoTitle() : ""); testParam.setLineSn(MesClient.getEffectiveLineSn()); testParam.setUcode(MesClient.user_menu != null ? MesClient.user_menu.getText().trim() : ""); testParam.setParam5(MesClient.configParam != null && MesClient.configParam.getProgramNo() != null ? MesClient.configParam.getProgramNo() : ""); testParam.setDeviceType(MesClient.configParam != null ? MesClient.configParam.getDevice() : "INNTAI"); testParam.setCreateTime(DateLocalUtils.getCurrentTime()); 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; } } static boolean isInntaiDevice(String device) { if (device == null) { return false; } String d = device.trim(); return "INNTAI".equalsIgnoreCase(d) || "中皖英泰".equals(d); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { System.out.println("exceptionCaught"); } private void sendHeartbeatPacket(ChannelHandlerContext ctx) { ctx.writeAndFlush(YtUtil.getSendByteBuf(YtUtil.getStateCommon())); } }