zsh_root
2025-12-10 8d662de2fd262b3a485f16e197cb4d0ca2a61cdf
src/PublicPannel/UpgradePanel.java
@@ -1,9 +1,15 @@
package PublicPannel;
import javax.swing.*;
import home.ButtonUtils;
import home.MainFrame;
import Ymodem.YModem;
import home.*;
import jiexi.DellTag55AA03;
import java.awt.*;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;
public class UpgradePanel extends JPanel {
    /**
@@ -15,68 +21,89 @@
    private JTextField filePathField;
    private JButton selectBinBtn;
    private JProgressBar progressBar;
    private JLabel selectFileLabel; // 新增:用于文件选择标签
    private JLabel progressLabel;   // 新增:用于进度标签
    private JLabel selectFileLabel;
    private JLabel progressLabel;
    // 新增:通信方式选择
    private JComboBox<String> communicationTypeCombo;
    private JLabel communicationTypeLabel;
    // 串口服务实例
    private SerialPortService serialService;
    // 网络通信面板引用
    private NetworkCommunicationPanel networkPanel;
    // 新增:升级相关状态
    private volatile boolean upgradeInProgress = false;
    private volatile boolean cancelUpgrade = false;
    
    public UpgradePanel(MainFrame mainFrame) {
        this.mainFrame = mainFrame;
        this.serialService = SerialCommunicationPanel.getSerialService();
        initializeUI();
    }
    
    private void initializeUI() {
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        
        // 内容面板 - 使用垂直布局,与BaseParameterPanel一致
        // 内容面板
        JPanel contentPanel = new JPanel();
        contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
        
        // 文件选择面板
        JPanel filePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        // 通信方式选择面板
        JPanel communicationPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        communicationTypeLabel = new JLabel(mainFrame.getString("communication.type"));
        communicationTypeCombo = new JComboBox<>(new String[]{
                mainFrame.getString("serial"),
                mainFrame.getString("tcp.client"),
                mainFrame.getString("tcp.server"),
                mainFrame.getString("udp")
        });
        communicationPanel.add(communicationTypeLabel);
        communicationPanel.add(communicationTypeCombo);
        
        // 文件选择面板
        JPanel filePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        filePathField = new JTextField();
        filePathField.setEditable(false);
        filePathField.setPreferredSize(new Dimension(200, 25)); // 设置文件路径宽度
        filePathField.setPreferredSize(new Dimension(200, 25));
        
        selectBinBtn = ButtonUtils.createBlueButton(mainFrame.getString("select.bin.file"));
        selectBinBtn.addActionListener(e -> selectBinFile());
        
        // 使用变量引用标签,以便后续更新
        selectFileLabel = new JLabel(mainFrame.getString("select.bin.file"));
        
        filePanel.add(selectFileLabel);
        filePanel.add(filePathField);
        filePanel.add(selectBinBtn);
        
        // 进度条和升级按钮面板 - 放在同一行
        // 进度条和升级按钮面板
        JPanel progressButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
        // 进度条
        progressBar = new JProgressBar(0, 100);
        progressBar.setStringPainted(true);
        progressBar.setVisible(false);
        progressBar.setPreferredSize(new Dimension(200, 25)); // 设置进度条宽度
        progressBar.setPreferredSize(new Dimension(200, 25));
        
        // 升级按钮
        upgradeBtn = ButtonUtils.createBlueButton(mainFrame.getString("start.upgrade"));
        upgradeBtn.addActionListener(e -> startUpgrade());
        
        // 使用变量引用进度标签,以便后续更新
        progressLabel = new JLabel(mainFrame.getString("upgrade.progress")); // 需要在语言资源文件中添加"upgrade.progress"键
        progressLabel = new JLabel(mainFrame.getString("upgrade.progress"));
        
        progressButtonPanel.add(progressLabel);
        progressButtonPanel.add(progressBar);
        progressButtonPanel.add(upgradeBtn);
        
        // 设置固定高度
        // 设置固定高度
        communicationPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        filePanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        progressButtonPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
        
        // 将所有组件添加到内容面板
        contentPanel.add(Box.createVerticalStrut(10)); // 顶部10像素间距
        // 将所有组件添加到内容面板
        contentPanel.add(Box.createVerticalStrut(10));
        contentPanel.add(communicationPanel);
        contentPanel.add(filePanel);
        contentPanel.add(progressButtonPanel);
        
        // 添加内容面板,不添加滚动面板
        add(contentPanel);
    }
    
@@ -88,7 +115,6 @@
        
        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            // 将选择的文件路径显示在文件路径框中
            String selectedFile = fileChooser.getSelectedFile().getAbsolutePath();
            filePathField.setText(selectedFile);
            
@@ -100,7 +126,7 @@
    }
    
    private void startUpgrade() {
        // 检查升级条件
        // 检查升级条件
        if (filePathField.getText().isEmpty()) {
            JOptionPane.showMessageDialog(this,
                mainFrame.getString("please.select.file.first"),
@@ -109,47 +135,544 @@
            return;
        }
        
        progressBar.setVisible(true);
        upgradeBtn.setEnabled(false);
        // 模拟升级进度
        Timer timer = new Timer(100, null);
        ActionListener actionListener = new ActionListener() {
            int progress = 0;
            @Override
            public void actionPerformed(java.awt.event.ActionEvent e) {
                progress += 5;
                progressBar.setValue(progress);
                if (progress >= 100) {
                    ((Timer) e.getSource()).stop();
                    upgradeBtn.setEnabled(true);
                    JOptionPane.showMessageDialog(UpgradePanel.this,
                        mainFrame.getString("upgrade.completed"),
                        mainFrame.getString("success"),
                        JOptionPane.INFORMATION_MESSAGE);
        // 检查通信连接状态
        String communicationType = (String) communicationTypeCombo.getSelectedItem();
        if (!checkCommunicationStatus(communicationType)) {
            return;
                }
        // 对于网络升级,检查是否选择了客户端
        if (!communicationType.equals(mainFrame.getString("serial"))) {
            if (!checkSelectedClient()) {
                return;
            }
        }
        // 确认升级
        int result = JOptionPane.showConfirmDialog(this,
                mainFrame.getString("upgrade.confirm.message"),
                mainFrame.getString("confirm.upgrade"),
                JOptionPane.YES_NO_OPTION,
                JOptionPane.QUESTION_MESSAGE);
        if (result != JOptionPane.YES_OPTION) {
            return;
        }
        upgradeBtn.setEnabled(false);
        selectBinBtn.setEnabled(false);
        progressBar.setVisible(true);
        progressBar.setValue(0);
        upgradeInProgress = true;
        cancelUpgrade = false;
        String filePath = filePathField.getText();
        new Thread(() -> {
            int retryCount = 0;
            final int maxRetries = 3;
            try {
                // 发送升级命令
                boolean success = sendUpgradeCommand(communicationType);
                if (!success) {
                    throw new IOException("Failed to send upgrade command");
                }
                // 等待设备准备升级
                Thread.sleep(1000);
                // 执行升级
                if (communicationType.equals(mainFrame.getString("serial"))) {
                    performSerialUpgrade(filePath);
                } else {
                    performNetworkUpgrade(filePath, communicationType);
                }
            } catch (Exception e) {
                if (retryCount < maxRetries && !cancelUpgrade) {
                    retryCount++;
                    try {
                        Thread.sleep(1000);
                        // 可以在这里添加重试逻辑
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                    }
                } else {
                    SwingUtilities.invokeLater(() -> {
                        if (!cancelUpgrade) {
                            JOptionPane.showMessageDialog(this,
                                    "升级失败" + ": " + e.getMessage(),
                                    "错误",
                                    JOptionPane.ERROR_MESSAGE);
                        }
                        restoreUIAfterUpgrade();
                    });
                }
            } finally {
                restoreUIAfterUpgrade();
            }
        }).start();
    }
    /**
     * 检查通信连接状态
     */
    private boolean checkCommunicationStatus(String communicationType) {
        if (communicationType.equals(mainFrame.getString("serial"))) {
            if (!serialService.isOpen()) {
                JOptionPane.showMessageDialog(this,
                        "请先打开串口连接",
                        "错误",
                        JOptionPane.ERROR_MESSAGE);
                return false;
            }
        } else {
            // 获取网络通信面板
            if (networkPanel == null) {
                networkPanel = mainFrame.getNetworkCommunicationPanel();
            }
            if (networkPanel == null || !networkPanel.isOpen()) {
                JOptionPane.showMessageDialog(this,
                        "请先打开网络连接",
                        "错误",
                        JOptionPane.ERROR_MESSAGE);
                return false;
            }
        }
        return true;
    }
    /**
     * 检查是否选择了客户端(针对网络升级)
     */
    private boolean checkSelectedClient() {
        if (networkPanel == null) {
            networkPanel = mainFrame.getNetworkCommunicationPanel();
        }
        // 获取当前选中的客户端
        String selectedClient = networkPanel.getSelectedClient();
        if (selectedClient == null || selectedClient.isEmpty()) {
            JOptionPane.showMessageDialog(this,
                    "请先选择要升级的客户端",
                    "错误",
                    JOptionPane.ERROR_MESSAGE);
            return false;
        }
        return true;
    }
    /**
     * 发送升级命令
     */
    private boolean sendUpgradeCommand(String communicationType) {
        byte[] upgradeCommand = DellTag55AA03.shengjizhiling();
        if (communicationType.equals(mainFrame.getString("serial"))) {
            // 串口升级期间停止数据捕获
            serialService.stopCapture();
            return serialService.send(upgradeCommand);
        } else {
            // 网络升级
            return sendNetworkData(upgradeCommand, "发送升级指令");
        }
    }
    /**
     * 执行串口升级
     */
    private void performSerialUpgrade(String filePath) throws Exception {
        InputStream inputStream = serialService.getInputStream();
        OutputStream outputStream = serialService.getOutputStream();
        if (inputStream == null || outputStream == null) {
            throw new IOException("串口不可用");
        }
        YModem ymodem = new YModem(inputStream, outputStream);
        File file = new File(filePath);
        YModem.ProgressCallback progressCallback = new YModem.ProgressCallback() {
            @Override
            public void onProgress(int currentBlock, int totalBlocks) {
                int progress = (int) ((currentBlock * 100.0) / totalBlocks);
                SwingUtilities.invokeLater(() -> {
                    progressBar.setValue(progress);
                });
            }
        };
        
        timer.addActionListener(actionListener);
        timer.start();
        ymodem.send(file.toPath(), progressCallback);
        SwingUtilities.invokeLater(() -> {
            JOptionPane.showMessageDialog(this, "升级成功", "成功", JOptionPane.INFORMATION_MESSAGE);
        });
    }
    /**
     * 执行网络升级
     */
    private void performNetworkUpgrade(String filePath, String communicationType) throws Exception {
        File file = new File(filePath);
        // 获取选中的客户端信息
        String selectedClient = networkPanel.getSelectedClient();
        if (selectedClient == null || selectedClient.isEmpty()) {
            throw new IOException("未选择客户端");
        }
        // 解析客户端地址
        String[] clientParts = selectedClient.split(":");
        if (clientParts.length != 2) {
            throw new IOException("客户端地址格式错误: " + selectedClient);
        }
        String clientIp = clientParts[0];
        int clientPort;
        try {
            clientPort = Integer.parseInt(clientParts[1]);
        } catch (NumberFormatException e) {
            throw new IOException("客户端端口格式错误: " + clientParts[1]);
        }
        // 创建网络输入输出流适配器
        NetworkStreamAdapter streamAdapter = new NetworkStreamAdapter(networkPanel, communicationType, clientIp, clientPort);
        InputStream inputStream = streamAdapter.getInputStream();
        OutputStream outputStream = streamAdapter.getOutputStream();
        if (inputStream == null || outputStream == null) {
            throw new IOException("网络流不可用");
        }
        YModem ymodem = new YModem(inputStream, outputStream);
        YModem.ProgressCallback progressCallback = new YModem.ProgressCallback() {
            @Override
            public void onProgress(int currentBlock, int totalBlocks) {
                int progress = (int) ((currentBlock * 100.0) / totalBlocks);
                SwingUtilities.invokeLater(() -> {
                    progressBar.setValue(progress);
                });
            }
        };
        try {
            ymodem.send(file.toPath(), progressCallback);
            if (!cancelUpgrade) {
                SwingUtilities.invokeLater(() -> {
                    JOptionPane.showMessageDialog(UpgradePanel.this,
                            "网络升级成功", "成功", JOptionPane.INFORMATION_MESSAGE);
                });
            }
        } catch (Exception e) {
            if (!cancelUpgrade) {
                throw e;
            }
        } finally {
            streamAdapter.close();
        }
    }
    /**
     * 发送网络数据
     */
    private boolean sendNetworkData(byte[] data, String description) {
        if (networkPanel == null) {
            networkPanel = mainFrame.getNetworkCommunicationPanel();
        }
        if (networkPanel != null) {
            // 使用NetworkCommunicationPanel的发送方法
            return networkPanel.sendNetworkDataInternal(data, description);
        }
        return false;
    }
    /**
     * 恢复UI状态
     */
    private void restoreUIAfterUpgrade() {
        SwingUtilities.invokeLater(() -> {
            upgradeInProgress = false;
            upgradeBtn.setEnabled(true);
            selectBinBtn.setEnabled(true);
            progressBar.setVisible(false);
            progressBar.setValue(0);
            // 重新启动串口数据捕获(如果是串口升级)
            if (serialService != null) {
                serialService.startCapture();
            }
        });
    }
    /**
     * 取消升级
     */
    public void cancelUpgrade() {
        if (upgradeInProgress) {
            cancelUpgrade = true;
            upgradeInProgress = false;
        }
    }
    /**
     * 设置网络通信面板引用
     */
    public void setNetworkCommunicationPanel(NetworkCommunicationPanel networkPanel) {
        this.networkPanel = networkPanel;
    }
    
    public void updateLanguage() {
        // 更新按钮文本
        // 更新通信方式选择
        communicationTypeLabel.setText(mainFrame.getString("communication.type"));
        communicationTypeCombo.removeAllItems();
        communicationTypeCombo.addItem(mainFrame.getString("serial"));
        communicationTypeCombo.addItem(mainFrame.getString("tcp.client"));
        communicationTypeCombo.addItem(mainFrame.getString("tcp.server"));
        communicationTypeCombo.addItem(mainFrame.getString("udp"));
        // 更新按钮文本
        selectBinBtn.setText(mainFrame.getString("select.bin.file"));
        upgradeBtn.setText(mainFrame.getString("start.upgrade"));
        
        // 更新标签文本
        // 更新标签文本
        selectFileLabel.setText(mainFrame.getString("select.bin.file"));
        progressLabel.setText(mainFrame.getString("upgrade.progress")); // 需要在语言资源文件中添加"upgrade.progress"键
        // 更新文件选择器对话框标题
        // 注意:这里无法直接更新已创建的JFileChooser,但下次打开时会使用新的文本
        progressLabel.setText(mainFrame.getString("upgrade.progress"));
        
        revalidate();
        repaint();
    }
    /**
     * 网络流适配器 - 内部类
     * 用于将网络通信适配为YModem所需的InputStream和OutputStream
     */
    private class NetworkStreamAdapter {
        private NetworkCommunicationPanel networkPanel;
        private String communicationType;
        private String clientIp;
        private int clientPort;
        private PipedInputStream inputStream;
        private PipedOutputStream outputStream;
        private boolean isConnected = false;
        // 用于数据接收的管道
        private PipedInputStream receiverInputStream;
        private PipedOutputStream receiverOutputStream;
        // 保存原始的数据监听器
        private NetworkBase.NetworkDataListener originalDataListener;
        public NetworkStreamAdapter(NetworkCommunicationPanel networkPanel, String communicationType,
                                    String clientIp, int clientPort) {
            this.networkPanel = networkPanel;
            this.communicationType = communicationType;
            this.clientIp = clientIp;
            this.clientPort = clientPort;
            initializeStreams();
            setupNetworkDataListener();
        }
        private void initializeStreams() {
            try {
                // 创建管道流用于数据发送
                inputStream = new PipedInputStream(8192); // 增加缓冲区大小
                outputStream = new PipedOutputStream(inputStream);
                // 创建管道流用于数据接收
                receiverInputStream = new PipedInputStream(8192);
                receiverOutputStream = new PipedOutputStream(receiverInputStream);
                isConnected = true;
                System.out.println("网络流适配器初始化成功");
            } catch (Exception e) {
                System.err.println("初始化网络流失败: " + e.getMessage());
                isConnected = false;
                throw new RuntimeException("网络流初始化失败", e);
            }
        }
        /**
         * 设置网络数据监听器
         */
        private void setupNetworkDataListener() {
            try {
                // 获取网络通信面板的当前网络实例
                NetworkBase currentNetwork = networkPanel.getCurrentNetwork();
                if (currentNetwork == null) {
                    System.err.println("网络连接未建立");
                    return;
                }
                // 保存原来的数据监听器
                originalDataListener = currentNetwork.getDataListener();
                // 创建升级专用的数据监听器
                NetworkBase.NetworkDataListener upgradeDataListener = new NetworkBase.NetworkDataListener() {
                    @Override
                    public void onDataReceived(byte[] data, String fromAddress) {
                        // 检查数据是否来自目标客户端
                        String expectedAddress = clientIp + ":" + clientPort;
                        if (expectedAddress.equals(fromAddress)) {
                            try {
                                // 将接收到的数据写入接收管道,供YModem读取
                                if (receiverOutputStream != null && !cancelUpgrade) {
                                    receiverOutputStream.write(data);
                                    receiverOutputStream.flush();
                                    // 调试信息
                                    System.out.println("接收到升级响应数据,长度: " + data.length + ",来自: " + fromAddress);
                                }
                            } catch (IOException e) {
                                System.err.println("写入接收管道失败: " + e.getMessage());
                                if (!cancelUpgrade) {
                                    SwingUtilities.invokeLater(() -> {
                                        JOptionPane.showMessageDialog(UpgradePanel.this,
                                                "升级数据接收失败: " + e.getMessage(),
                                                "错误", JOptionPane.ERROR_MESSAGE);
                                    });
                                }
                            }
                        } else {
                            // 非目标客户端的数据,可以记录日志但忽略
                            System.out.println("忽略非目标客户端数据,来自: " + fromAddress + ",期望: " + expectedAddress);
                        }
                        // 同时调用原来的监听器,保持其他功能正常
                        if (originalDataListener != null) {
                            originalDataListener.onDataReceived(data, fromAddress);
                        }
                    }
                    @Override
                    public void onStatusChanged(String status, boolean isConnected) {
                        // 传递状态变化给原来的监听器
                        if (originalDataListener != null) {
                            originalDataListener.onStatusChanged(status, isConnected);
                        }
                        // 如果连接断开且正在升级,需要处理
                        if (!isConnected && upgradeInProgress) {
                            System.err.println("网络连接断开,升级可能失败");
                            if (!cancelUpgrade) {
                                SwingUtilities.invokeLater(() -> {
                                    JOptionPane.showMessageDialog(UpgradePanel.this,
                                            "网络连接已断开,升级失败",
                                            "错误", JOptionPane.ERROR_MESSAGE);
                                    cancelUpgrade = true;
                                });
                            }
                        }
                    }
                    @Override
                    public void onError(String errorMessage) {
                        // 传递错误给原来的监听器
                        if (originalDataListener != null) {
                            originalDataListener.onError(errorMessage);
                        }
                        // 如果正在升级,需要处理错误
                        if (upgradeInProgress && !cancelUpgrade) {
                            System.err.println("升级过程中发生网络错误: " + errorMessage);
                            SwingUtilities.invokeLater(() -> {
                                JOptionPane.showMessageDialog(UpgradePanel.this,
                                        "网络错误: " + errorMessage,
                                        "错误", JOptionPane.ERROR_MESSAGE);
                            });
                        }
                    }
                };
                // 设置新的数据监听器
                currentNetwork.setDataListener(upgradeDataListener);
                System.out.println("升级数据监听器已设置,目标客户端: " + clientIp + ":" + clientPort);
            } catch (Exception e) {
                System.err.println("设置网络数据监听器失败: " + e.getMessage());
                throw new RuntimeException("网络数据监听器初始化失败", e);
            }
        }
        public InputStream getInputStream() {
            return receiverInputStream;
        }
        public OutputStream getOutputStream() {
            return new NetworkOutputStream();
        }
        public void close() {
            try {
                // 恢复原始的数据监听器
                if (networkPanel != null && networkPanel.getCurrentNetwork() != null && originalDataListener != null) {
                    networkPanel.getCurrentNetwork().setDataListener(originalDataListener);
                    System.out.println("已恢复原始数据监听器");
                }
                if (inputStream != null) inputStream.close();
                if (outputStream != null) outputStream.close();
                if (receiverInputStream != null) receiverInputStream.close();
                if (receiverOutputStream != null) receiverOutputStream.close();
                System.out.println("网络流适配器已关闭");
            } catch (IOException e) {
                System.err.println("关闭网络流失败: " + e.getMessage());
            }
        }
        /**
         * 网络输出流实现
         * 将YModem写入的数据通过网络发送到指定客户端
         */
        private class NetworkOutputStream extends OutputStream {
            @Override
            public void write(int b) throws IOException {
                write(new byte[]{(byte) b}, 0, 1);
            }
            @Override
            public void write(byte[] b, int off, int len) throws IOException {
                if (cancelUpgrade) {
                    throw new IOException("升级已取消");
                }
                byte[] dataToSend = new byte[len];
                System.arraycopy(b, off, dataToSend, 0, len);
                boolean success = false;
                if (communicationType.equals(mainFrame.getString("udp"))) {
                    // UDP模式发送
                    success = networkPanel.sendUdpData(dataToSend, clientIp, clientPort, "升级数据");
                } else if (communicationType.equals(mainFrame.getString("tcp.server"))) {
                    // TCP Server模式发送到指定客户端
                    String clientKey = clientIp + ":" + clientPort;
                    success = networkPanel.sendTcpDataToClient(clientKey, dataToSend, "升级数据");
                }
                if (!success) {
                    throw new IOException("网络发送失败");
                }
                // 调试信息
                System.out.println("发送升级数据,长度: " + len);
            }
            @Override
            public void flush() throws IOException {
                // 网络发送立即生效,无需特殊处理
            }
            @Override
            public void close() throws IOException {
                // 不关闭底层网络连接
            }
        }
    }
}