package PublicPannel;
|
|
import javax.swing.*;
|
|
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 {
|
/**
|
*
|
*/
|
private static final long serialVersionUID = 1L;
|
private MainFrame mainFrame;
|
private JButton upgradeBtn;
|
private JTextField filePathField;
|
private JButton selectBinBtn;
|
private JProgressBar progressBar;
|
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));
|
|
// 内容面板
|
JPanel contentPanel = new JPanel();
|
contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
|
|
// 通信方式选择面板
|
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));
|
|
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));
|
|
upgradeBtn = ButtonUtils.createBlueButton(mainFrame.getString("start.upgrade"));
|
upgradeBtn.addActionListener(e -> startUpgrade());
|
|
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));
|
contentPanel.add(communicationPanel);
|
contentPanel.add(filePanel);
|
contentPanel.add(progressButtonPanel);
|
|
add(contentPanel);
|
}
|
|
private void selectBinFile() {
|
JFileChooser fileChooser = new JFileChooser();
|
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
fileChooser.setDialogTitle(mainFrame.getString("select.bin.file"));
|
fileChooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("BIN files (*.bin)", "bin"));
|
|
int result = fileChooser.showOpenDialog(this);
|
if (result == JFileChooser.APPROVE_OPTION) {
|
String selectedFile = fileChooser.getSelectedFile().getAbsolutePath();
|
filePathField.setText(selectedFile);
|
|
JOptionPane.showMessageDialog(this,
|
mainFrame.getString("selected.file") + ": " + selectedFile,
|
mainFrame.getString("file.selected"),
|
JOptionPane.INFORMATION_MESSAGE);
|
}
|
}
|
|
private void startUpgrade() {
|
// 检查升级条件
|
if (filePathField.getText().isEmpty()) {
|
JOptionPane.showMessageDialog(this,
|
mainFrame.getString("please.select.file.first"),
|
mainFrame.getString("warning"),
|
JOptionPane.WARNING_MESSAGE);
|
return;
|
}
|
|
// 检查通信连接状态
|
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);
|
});
|
}
|
};
|
|
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"));
|
|
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 {
|
// 不关闭底层网络连接
|
}
|
}
|
}
|
|
}
|