Browse Source

测试工具

wangxichen 3 ngày trước cách đây
mục cha
commit
c44a47b13a
2 tập tin đã thay đổi với 583 bổ sung1 xóa
  1. 582 0
      src/com/mes/ui/PlcSignalPanel.java
  2. 1 1
      src/resources/config/config.properties

+ 582 - 0
src/com/mes/ui/PlcSignalPanel.java

@@ -0,0 +1,582 @@
+package com.mes.ui;
+
+import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
+import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+import java.awt.*;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * OP50 PLC 信号监控面板
+ * 独立运行,不依赖 MES 服务器连接,直连 S7-1200 读写 DB200 点位
+ */
+public class PlcSignalPanel extends JFrame {
+
+    // ===== 点位定义(与 PlcUtil 保持一致)=====
+    private static final String DB = "DB200";
+    private static final String A_PERMIT = DB + ".0.1";     // A面MES允许启动
+    private static final String B_PERMIT = DB + ".38.0";    // B面MES允许启动
+    private static final String A_STATUS = DB + ".34";      // A面状态 Int16
+    private static final String B_STATUS = DB + ".72";      // B面状态 Int16
+    private static final String A_POSITION = DB + ".156.3"; // A面到位
+    private static final String B_POSITION = DB + ".156.4"; // B面到位
+
+    /** 焊点点位:名称, 完成标志, 序号, 电流, 电压, 送丝速度, 焊接速度 */
+    private static final String[][] WELD_POINTS = {
+            {"R1", "76.1", "78", "80", "84", "88", "92"},
+            {"R2", "96.2", "98", "100", "104", "108", "112"},
+            {"R3", "116.2", "118", "120", "124", "128", "132"},
+            {"R4", "136.2", "138", "140", "144", "148", "152"}
+    };
+
+    private static final Color GREEN = new Color(0, 200, 0);
+    private static final Color YELLOW = new Color(230, 170, 0);
+    private static final Color GRAY = Color.GRAY;
+    private static final Color BLUE = new Color(0, 100, 200);
+
+    private final String defaultIp;
+    private volatile S7PLC s7PLC;
+    private volatile boolean connected = false;
+
+    // 连接控制
+    private JTextField ipField;
+    private JButton connectBtn;
+    private JButton disconnectBtn;
+    private JLabel connLight;
+
+    // 转台位置
+    private JLabel lightPosA;
+    private JLabel lightPosB;
+    private JLabel valueCurSide;
+
+    // MES允许启动
+    private JLabel lightPermitA;
+    private JLabel lightPermitB;
+    private JButton permitSetA;
+    private JButton permitResetA;
+    private JButton permitSetB;
+    private JButton permitResetB;
+
+    // 焊接状态
+    private JLabel lightStatusA;
+    private JLabel lightStatusB;
+    private JLabel valueStatusA;
+    private JLabel valueStatusB;
+    private JButton ackBtnA;
+    private JButton ackBtnB;
+
+    // 焊接参数表
+    private DefaultTableModel weldModel;
+
+    // 日志
+    private JTextArea logArea;
+
+    private Timer monitorTimer;
+
+    public PlcSignalPanel(String defaultIp) {
+        this.defaultIp = (defaultIp == null || defaultIp.trim().isEmpty()) ? "192.168.1.1" : defaultIp.trim();
+        initUI();
+        startMonitor();
+    }
+
+    private void initUI() {
+        setTitle("OP50 PLC 信号监控 - 框架总成焊接1");
+        setSize(900, 900);
+        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+        setLocationRelativeTo(null);
+
+        JPanel main = new JPanel(new BorderLayout(8, 8));
+        main.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
+
+        JPanel top = new JPanel();
+        top.setLayout(new BoxLayout(top, BoxLayout.Y_AXIS));
+        top.add(createConnPanel());
+        top.add(createPositionPanel());
+        top.add(createPermitPanel());
+        top.add(createStatusPanel());
+        main.add(top, BorderLayout.NORTH);
+
+        JPanel center = new JPanel(new BorderLayout(8, 8));
+        center.add(createWeldTablePanel(), BorderLayout.CENTER);
+        center.add(createLogPanel(), BorderLayout.SOUTH);
+        main.add(center, BorderLayout.CENTER);
+
+        add(main);
+    }
+
+    // 连接控制面板
+    private JPanel createConnPanel() {
+        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 5));
+        panel.setBorder(BorderFactory.createTitledBorder("连接控制"));
+
+        panel.add(label("PLC IP:", 14));
+
+        ipField = new JTextField(defaultIp, 14);
+        ipField.setFont(new Font("Consolas", Font.PLAIN, 14));
+        panel.add(ipField);
+
+        connectBtn = new JButton("连接");
+        connectBtn.addActionListener(e -> doConnect());
+        panel.add(connectBtn);
+
+        disconnectBtn = new JButton("断开");
+        disconnectBtn.setEnabled(false);
+        disconnectBtn.addActionListener(e -> doDisconnect());
+        panel.add(disconnectBtn);
+
+        connLight = light(GRAY);
+        panel.add(connLight);
+
+        panel.add(label("S7-1200 / DB200", 12));
+        return panel;
+    }
+
+    // 转台位置面板
+    private JPanel createPositionPanel() {
+        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 12, 5));
+        panel.setBorder(BorderFactory.createTitledBorder("转台位置(只读)"));
+
+        panel.add(label("A面到位 " + A_POSITION, 13));
+        lightPosA = light(GRAY);
+        panel.add(lightPosA);
+
+        panel.add(label("     B面到位 " + B_POSITION, 13));
+        lightPosB = light(GRAY);
+        panel.add(lightPosB);
+
+        panel.add(label("     推算当前面:", 13));
+        valueCurSide = new JLabel("--");
+        valueCurSide.setFont(new Font("微软雅黑", Font.BOLD, 16));
+        valueCurSide.setForeground(BLUE);
+        panel.add(valueCurSide);
+
+        return panel;
+    }
+
+    // MES允许启动面板
+    private JPanel createPermitPanel() {
+        JPanel panel = new JPanel(new GridLayout(2, 1, 4, 4));
+        panel.setBorder(BorderFactory.createTitledBorder("MES允许启动(可读写 — 写操作会真实影响 PLC)"));
+
+        JPanel rowA = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 3));
+        rowA.add(fixedLabel("A面MES允许启动 " + A_PERMIT, 230));
+        lightPermitA = light(GRAY);
+        rowA.add(lightPermitA);
+        permitSetA = new JButton("置位 true");
+        permitSetA.addActionListener(e -> writePermit("A", true));
+        rowA.add(permitSetA);
+        permitResetA = new JButton("复位 false");
+        permitResetA.addActionListener(e -> writePermit("A", false));
+        rowA.add(permitResetA);
+        panel.add(rowA);
+
+        JPanel rowB = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 3));
+        rowB.add(fixedLabel("B面MES允许启动 " + B_PERMIT, 230));
+        lightPermitB = light(GRAY);
+        rowB.add(lightPermitB);
+        permitSetB = new JButton("置位 true");
+        permitSetB.addActionListener(e -> writePermit("B", true));
+        rowB.add(permitSetB);
+        permitResetB = new JButton("复位 false");
+        permitResetB.addActionListener(e -> writePermit("B", false));
+        rowB.add(permitResetB);
+        panel.add(rowB);
+
+        return panel;
+    }
+
+    // 焊接状态面板
+    private JPanel createStatusPanel() {
+        JPanel panel = new JPanel(new GridLayout(2, 1, 4, 4));
+        panel.setBorder(BorderFactory.createTitledBorder("焊接状态(只读 Int16 — 0空闲/1运行中/2完成)"));
+
+        JPanel rowA = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 3));
+        rowA.add(fixedLabel("A面状态 " + A_STATUS, 180));
+        lightStatusA = light(GRAY);
+        rowA.add(lightStatusA);
+        valueStatusA = valueLabel("--");
+        rowA.add(valueStatusA);
+        ackBtnA = new JButton("应答清零");
+        ackBtnA.addActionListener(e -> ackStatus("A"));
+        rowA.add(ackBtnA);
+        panel.add(rowA);
+
+        JPanel rowB = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 3));
+        rowB.add(fixedLabel("B面状态 " + B_STATUS, 180));
+        lightStatusB = light(GRAY);
+        rowB.add(lightStatusB);
+        valueStatusB = valueLabel("--");
+        rowB.add(valueStatusB);
+        ackBtnB = new JButton("应答清零");
+        ackBtnB.addActionListener(e -> ackStatus("B"));
+        rowB.add(ackBtnB);
+        panel.add(rowB);
+
+        return panel;
+    }
+
+    // 焊接参数表格面板
+    private JPanel createWeldTablePanel() {
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.setBorder(BorderFactory.createTitledBorder("焊接参数(只读 — R1~R4 四个焊点)"));
+
+        String[] cols = {"焊点", "完成标志", "序号", "电流", "电压", "送丝速度", "焊接速度"};
+        weldModel = new DefaultTableModel(cols, 0) {
+            @Override
+            public boolean isCellEditable(int row, int column) {
+                return false;
+            }
+        };
+
+        // 初始化 4 行
+        for (String[] point : WELD_POINTS) {
+            weldModel.addRow(new Object[]{point[0], "--", "--", "--", "--", "--", "--"});
+        }
+
+        JTable table = new JTable(weldModel);
+        table.setFont(new Font("Consolas", Font.PLAIN, 13));
+        table.setRowHeight(28);
+        table.getTableHeader().setFont(new Font("微软雅黑", Font.BOLD, 13));
+
+        // 完成标志列居中,用绿点显示
+        DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
+        centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);
+        table.getColumnModel().getColumn(1).setCellRenderer(centerRenderer);
+
+        JScrollPane scroll = new JScrollPane(table);
+        scroll.setPreferredSize(new Dimension(0, 150));
+        panel.add(scroll, BorderLayout.CENTER);
+
+        return panel;
+    }
+
+    // 日志面板
+    private JPanel createLogPanel() {
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.setBorder(BorderFactory.createTitledBorder("操作日志"));
+
+        logArea = new JTextArea(6, 0);
+        logArea.setEditable(false);
+        logArea.setFont(new Font("微软雅黑", Font.PLAIN, 12));
+        JScrollPane scroll = new JScrollPane(logArea);
+        panel.add(scroll, BorderLayout.CENTER);
+
+        return panel;
+    }
+
+    // 连接 PLC
+    private void doConnect() {
+        String ip = ipField.getText().trim();
+        if (ip.isEmpty()) {
+            JOptionPane.showMessageDialog(this, "请输入 PLC IP 地址", "提示", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+        connectBtn.setEnabled(false);
+        log("连接中: " + ip);
+
+        new Thread(() -> {
+            try {
+                s7PLC = new S7PLC(EPlcType.S1200, ip);
+                // 测试连接
+                s7PLC.readBoolean(A_POSITION);
+                connected = true;
+                SwingUtilities.invokeLater(() -> {
+                    connectBtn.setEnabled(false);
+                    disconnectBtn.setEnabled(true);
+                    ipField.setEnabled(false);
+                    log("✓ 连接成功: " + ip);
+                });
+            } catch (Exception e) {
+                connected = false;
+                SwingUtilities.invokeLater(() -> {
+                    connectBtn.setEnabled(true);
+                    disconnectBtn.setEnabled(false);
+                    log("✗ 连接失败: " + e.getMessage());
+                    JOptionPane.showMessageDialog(this, "连接失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
+                });
+            }
+        }, "PLC-Connect").start();
+    }
+
+    // 断开 PLC
+    private void doDisconnect() {
+        try {
+            if (s7PLC != null) {
+                s7PLC.close();
+            }
+        } catch (Exception e) {
+            log("断开异常: " + e.getMessage());
+        }
+        connected = false;
+        s7PLC = null;
+        connectBtn.setEnabled(true);
+        disconnectBtn.setEnabled(false);
+        ipField.setEnabled(true);
+        log("已断开连接");
+    }
+
+    // 写许可信号
+    private void writePermit(String side, boolean value) {
+        if (!connected) {
+            JOptionPane.showMessageDialog(this, "PLC 未连接", "提示", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+
+        String addr = side.equals("A") ? A_PERMIT : B_PERMIT;
+        int confirm = JOptionPane.showConfirmDialog(this,
+                "确认写入 " + addr + " = " + value + " ?\n这会影响 PLC 实际状态!",
+                "写操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
+
+        if (confirm != JOptionPane.YES_OPTION) {
+            log("已取消写操作: " + addr);
+            return;
+        }
+
+        new Thread(() -> {
+            try {
+                s7PLC.writeBoolean(addr, value);
+                log("✓ 写入成功: " + addr + " = " + value);
+            } catch (Exception e) {
+                log("✗ 写入失败: " + addr + " - " + e.getMessage());
+                SwingUtilities.invokeLater(() ->
+                        JOptionPane.showMessageDialog(this, "写入失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE));
+            }
+        }, "PLC-Write").start();
+    }
+
+    // 应答清零状态
+    private void ackStatus(String side) {
+        if (!connected) {
+            JOptionPane.showMessageDialog(this, "PLC 未连接", "提示", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+
+        String addr = side.equals("A") ? A_STATUS : B_STATUS;
+        int confirm = JOptionPane.showConfirmDialog(this,
+                "确认应答清零 " + addr + " = 0 ?\n这会清除 PLC 焊接完成标志!",
+                "写操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
+
+        if (confirm != JOptionPane.YES_OPTION) {
+            log("已取消应答: " + addr);
+            return;
+        }
+
+        new Thread(() -> {
+            try {
+                s7PLC.writeInt16(addr, (short) 0);
+                log("✓ 应答成功: " + addr + " = 0");
+            } catch (Exception e) {
+                log("✗ 应答失败: " + addr + " - " + e.getMessage());
+                SwingUtilities.invokeLater(() ->
+                        JOptionPane.showMessageDialog(this, "应答失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE));
+            }
+        }, "PLC-Ack").start();
+    }
+
+    // 启动监控定时器
+    private void startMonitor() {
+        monitorTimer = new Timer();
+        monitorTimer.schedule(new TimerTask() {
+            @Override
+            public void run() {
+                updateMonitor();
+            }
+        }, 500, 1000);  // 首次 0.5s,之后每 1s
+    }
+
+    // 更新监控数据
+    private void updateMonitor() {
+        boolean isConnected = connected && s7PLC != null;
+        SwingUtilities.invokeLater(() -> updateLight(connLight, isConnected));
+
+        if (!isConnected) {
+            SwingUtilities.invokeLater(this::clearAllDisplays);
+            return;
+        }
+
+        try {
+            // 转台位置
+            boolean posA = readBoolSafe(A_POSITION);
+            boolean posB = readBoolSafe(B_POSITION);
+
+            // MES允许启动
+            boolean permitA = readBoolSafe(A_PERMIT);
+            boolean permitB = readBoolSafe(B_PERMIT);
+
+            // 焊接状态
+            int statusA = readInt16Safe(A_STATUS);
+            int statusB = readInt16Safe(B_STATUS);
+
+            // 焊接参数
+            Object[][] weldData = new Object[4][7];
+            for (int i = 0; i < WELD_POINTS.length; i++) {
+                String[] point = WELD_POINTS[i];
+                weldData[i][0] = point[0]; // 焊点名
+                weldData[i][1] = readBoolSafe(DB + "." + point[1]) ? "●" : "○"; // 完成标志
+                weldData[i][2] = readInt16Safe(DB + "." + point[2]); // 序号
+                weldData[i][3] = String.format("%.1f", readFloat32Safe(DB + "." + point[3])); // 电流
+                weldData[i][4] = String.format("%.1f", readFloat32Safe(DB + "." + point[4])); // 电压
+                weldData[i][5] = String.format("%.1f", readFloat32Safe(DB + "." + point[5])); // 送丝速度
+                weldData[i][6] = String.format("%.1f", readFloat32Safe(DB + "." + point[6])); // 焊接速度
+            }
+
+            // UI 更新
+            SwingUtilities.invokeLater(() -> {
+                // 转台位置
+                updateLight(lightPosA, posA);
+                updateLight(lightPosB, posB);
+                valueCurSide.setText(getCurSide(posA, posB));
+
+                // MES允许启动
+                updateLight(lightPermitA, permitA);
+                updateLight(lightPermitB, permitB);
+
+                // 焊接状态
+                updateStatusDisplay(statusA, lightStatusA, valueStatusA);
+                updateStatusDisplay(statusB, lightStatusB, valueStatusB);
+
+                // 焊接参数
+                for (int i = 0; i < weldData.length; i++) {
+                    for (int j = 0; j < weldData[i].length; j++) {
+                        weldModel.setValueAt(weldData[i][j], i, j);
+                    }
+                }
+            });
+
+        } catch (Exception e) {
+            // 不阻塞轮询,静默记录
+            System.err.println("轮询异常: " + e.getMessage());
+        }
+    }
+
+    // 安全读取 Bool
+    private boolean readBoolSafe(String addr) {
+        try {
+            return s7PLC.readBoolean(addr);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    // 安全读取 Int16
+    private int readInt16Safe(String addr) {
+        try {
+            return s7PLC.readInt16(addr);
+        } catch (Exception e) {
+            return -1;
+        }
+    }
+
+    // 安全读取 Float32
+    private float readFloat32Safe(String addr) {
+        try {
+            return s7PLC.readFloat32(addr);
+        } catch (Exception e) {
+            return 0f;
+        }
+    }
+
+    // 推算当前面
+    private String getCurSide(boolean posA, boolean posB) {
+        if (posA) return "A";
+        if (posB) return "B";
+        return "--";
+    }
+
+    // 更新状态显示
+    private void updateStatusDisplay(int status, JLabel light, JLabel valueLabel) {
+        String text;
+        Color color;
+        if (status == 0) {
+            text = "0 空闲";
+            color = GRAY;
+        } else if (status == 1) {
+            text = "1 运行中";
+            color = YELLOW;
+        } else if (status == 2) {
+            text = "2 完成";
+            color = GREEN;
+        } else {
+            text = status + " (?)";
+            color = GRAY;
+        }
+        valueLabel.setText(text);
+        updateLight(light, status > 0);
+        light.setForeground(color);
+    }
+
+    // 清空所有显示
+    private void clearAllDisplays() {
+        updateLight(lightPosA, false);
+        updateLight(lightPosB, false);
+        valueCurSide.setText("--");
+        updateLight(lightPermitA, false);
+        updateLight(lightPermitB, false);
+        updateLight(lightStatusA, false);
+        updateLight(lightStatusB, false);
+        valueStatusA.setText("--");
+        valueStatusB.setText("--");
+        for (int i = 0; i < weldModel.getRowCount(); i++) {
+            for (int j = 1; j < weldModel.getColumnCount(); j++) {
+                weldModel.setValueAt("--", i, j);
+            }
+        }
+    }
+
+    // 更新指示灯颜色
+    private void updateLight(JLabel light, boolean on) {
+        light.setForeground(on ? GREEN : GRAY);
+    }
+
+    // 日志记录
+    private void log(String msg) {
+        String time = new SimpleDateFormat("HH:mm:ss").format(new Date());
+        SwingUtilities.invokeLater(() -> {
+            logArea.append("[" + time + "] " + msg + "\n");
+            logArea.setCaretPosition(logArea.getDocument().getLength());
+        });
+    }
+
+    // 停止监控
+    public void stopMonitor() {
+        if (monitorTimer != null) {
+            monitorTimer.cancel();
+        }
+    }
+
+    // ===== UI 组件工具方法 =====
+
+    private JLabel light(Color color) {
+        JLabel light = new JLabel("●");
+        light.setFont(new Font("Arial", Font.BOLD, 28));
+        light.setForeground(color);
+        return light;
+    }
+
+    private JLabel label(String text, int fontSize) {
+        JLabel label = new JLabel(text);
+        label.setFont(new Font("微软雅黑", Font.PLAIN, fontSize));
+        return label;
+    }
+
+    private JLabel fixedLabel(String text, int width) {
+        JLabel label = new JLabel(text);
+        label.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        label.setPreferredSize(new Dimension(width, 25));
+        return label;
+    }
+
+    private JLabel valueLabel(String text) {
+        JLabel label = new JLabel(text);
+        label.setFont(new Font("Consolas", Font.BOLD, 15));
+        label.setForeground(BLUE);
+        return label;
+    }
+}
+

+ 1 - 1
src/resources/config/config.properties

@@ -1,4 +1,4 @@
-mes.gw=OP050A
+mes.gw=OP050
 #mes.server_ip=127.0.0.1
 mes.server_ip=192.168.114.99
 mes.tcp_port=3000