package home; import javax.swing.*; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import PublicPannel.AntiCollisionPanel; import PublicPannel.BaseParameterPanel; import PublicPannel.BaseStationPanel; import PublicPannel.TagPanel; import PublicPannel.UpgradePanel; import jiexi.DellTag55AA03; import java.awt.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import com.fazecast.jSerialComm.SerialPort; public class SerialCommunicationPanel extends JPanel { /** * */ private static final long serialVersionUID = 7501141001234273316L; private MainFrame mainFrame; private JComboBox serialPortCombo, baudRateCombo; private JButton openBtn; private static JTabbedPane rightTabbedPane; private BaseParameterPanel baseParamPanel; private BaseStationPanel baseStationPanel; private TagPanel tagPanel; private AntiCollisionPanel antiCollisionPanel; private UpgradePanel upgradePanel; private JButton readParamsBtn, saveParamsBtn, restartDeviceBtn, resetFactoryBtn; private boolean isOpen = false; // 新增:保存标签引用用于语言切换 private JLabel selectSerialLabel, baudRateLabel; // 新增:串口服务实例 private SerialPortService serialService; // 新增:数据日志面板引用 private DataLogPanel dataLogPanel; // 配置命令常量 private static final String READ_CONFIG_CMD = "55AA03060102800073FF"; // 读取配置命令 private static final String READ_CONFIG_CMD2 = "55AA03060102800073FF"; // 读取配置命令 private static final String RESTART_DEVICE_CMD = "55AA03016001FF"; // 重启设备命令 private static final String RESET_FACTORY_CMD = "55AA03016002FF"; // 恢复出厂设置命令 public SerialCommunicationPanel(MainFrame mainFrame) { this.mainFrame = mainFrame; this.serialService = new SerialPortService(); // 初始化串口服务 initializeUI(); setupButtonListeners(); } private void initializeUI() { setLayout(new BorderLayout()); // 控制面板 JPanel controlPanel = createControlPanel(); // 主分割面板 - 使用水平分割 JSplitPane mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); mainSplitPane.setDividerLocation(320); // 基础参数面板 JPanel leftPanel = createBaseParameterPanel(); // 右侧功能面板 JPanel rightPanel = createRightPanel(); rightPanel.setBorder(null); // 移除面板边框 mainSplitPane.setLeftComponent(leftPanel); mainSplitPane.setRightComponent(rightPanel); add(controlPanel, BorderLayout.NORTH); add(mainSplitPane, BorderLayout.CENTER); // 底部按钮面板 add(createBottomButtonPanel(), BorderLayout.SOUTH); } /** * 设置按钮监听器 */ private void setupButtonListeners() { readParamsBtn.addActionListener(e -> readParameters()); saveParamsBtn.addActionListener(e -> saveParameters()); restartDeviceBtn.addActionListener(e -> restartDevice()); resetFactoryBtn.addActionListener(e -> resetFactory()); } /** * 读取参数 */ private void readParameters() { if (!serialService.isOpen()) { JOptionPane.showMessageDialog(this, getString("open_serial_first"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } // 根据当前选中的面板决定使用哪个指令和解析方法 String readCommand; final boolean useParse2; // 声明为final int selectedPanelIndex = getCurrentSelectedPanelIndex(); if (selectedPanelIndex == 2) { // 防撞面板的索引为2 readCommand = READ_CONFIG_CMD2; useParse2 = true; } else { readCommand = READ_CONFIG_CMD; useParse2 = false; } byte[] data = hexStringToByteArray(readCommand); if (data == null) { JOptionPane.showMessageDialog(this, getString("invalid_hex_format"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } // 新增:在数据日志窗口显示发送的指令 if (dataLogPanel != null) { dataLogPanel.addLogData(data, "发送读取配置指令"); } AtomicBoolean responseReceived = new AtomicBoolean(false); AtomicBoolean operationCompleted = new AtomicBoolean(false); // 按钮视觉反馈 readParamsBtn.setBackground(Color.GREEN); readParamsBtn.setEnabled(false); // 设置响应消费者 Consumer responseConsumer = responseData -> { if (operationCompleted.get()) return; serialService.setResponseConsumer(null); operationCompleted.set(true); String hexResponse = bytesToHex(responseData); if (hexResponse.startsWith("55AA03")) { // 根据面板选择使用parse还是parse2方法 DellTag55AA03.ParseResult result; if (useParse2) { result = DellTag55AA03.parse2(hexResponse, "127.0.0.1", 0); } else { result = DellTag55AA03.parse(hexResponse, "127.0.0.1", 0); } if (result != null) { SwingUtilities.invokeLater(() -> { updateParameterFields(result); responseReceived.set(true); JOptionPane.showMessageDialog(this, getString("config_read_success"), getString("info"), JOptionPane.INFORMATION_MESSAGE); // 恢复按钮状态 readParamsBtn.setBackground(new Color(70, 130, 180)); readParamsBtn.setEnabled(true); }); return; } } // 响应数据不合法 SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(this, getString("invalid_response_data"), getString("error"), JOptionPane.ERROR_MESSAGE); readParamsBtn.setBackground(new Color(70, 130, 180)); readParamsBtn.setEnabled(true); }); }; // 在独立线程中执行串口操作 new Thread(() -> { serialService.setResponseConsumer(responseConsumer); boolean success = serialService.send(data); if (!success) { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(this, getString("send_data_failed"), getString("error"), JOptionPane.ERROR_MESSAGE); serialService.setResponseConsumer(null); readParamsBtn.setBackground(new Color(70, 130, 180)); readParamsBtn.setEnabled(true); }); return; } // 等待响应,最长5秒 long startTime = System.currentTimeMillis(); while (!operationCompleted.get() && (System.currentTimeMillis() - startTime) < 5000) { try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } // 检查是否超时 if (!operationCompleted.get()) { operationCompleted.set(true); SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(this, getString("config_read_timeout"), getString("error"), JOptionPane.ERROR_MESSAGE); serialService.setResponseConsumer(null); readParamsBtn.setBackground(new Color(70, 130, 180)); readParamsBtn.setEnabled(true); }); } }).start(); } /** * 更新参数字段到界面 - 使用新的工具类 */ private void updateParameterFields(DellTag55AA03.ParseResult result) { PanelFieldUpdater.updateAllPanels(result, baseParamPanel, baseStationPanel, tagPanel, antiCollisionPanel, upgradePanel); } /** * 保存参数 - 修复后的方法 */ private void saveParameters() { if (!serialService.isOpen()) { JOptionPane.showMessageDialog(this, getString("open_serial_first"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } try { // 使用工具类从各个面板收集参数并构建配置数据 byte[] configData = PanelFieldUpdater.collectParametersToConfig( baseParamPanel, baseStationPanel, tagPanel, antiCollisionPanel, upgradePanel); if (configData == null) { JOptionPane.showMessageDialog(this, getString("invalid_config_data"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } // 新增:在数据日志窗口显示发送的配置数据 if (dataLogPanel != null) { dataLogPanel.addLogData(configData, "发送保存配置指令"); } boolean success = serialService.send(configData); if (success) { JOptionPane.showMessageDialog(this, getString("config_save_success"), getString("info"), JOptionPane.INFORMATION_MESSAGE); } else { JOptionPane.showMessageDialog(this, getString("send_data_failed"), getString("error"), JOptionPane.ERROR_MESSAGE); } } catch (Exception e) { JOptionPane.showMessageDialog(this, getString("config_save_failed") + ": " + e.getMessage(), getString("error"), JOptionPane.ERROR_MESSAGE); return; } // 按钮视觉反馈 saveParamsBtn.setBackground(Color.GREEN); Timer timer = new Timer(500, e -> { saveParamsBtn.setBackground(new Color(70, 130, 180)); }); timer.setRepeats(false); timer.start(); } /** * 重启设备 - 修复方法 */ private void restartDevice() { if (!serialService.isOpen()) { JOptionPane.showMessageDialog(this, getString("open_serial_first"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } byte[] data = hexStringToByteArray(RESTART_DEVICE_CMD); if (data == null) { JOptionPane.showMessageDialog(this, getString("invalid_hex_format"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } // 新增:在数据日志窗口显示发送的指令 if (dataLogPanel != null) { dataLogPanel.addLogData(data, "发送重启设备指令"); } boolean success = serialService.send(data); if (success) { JOptionPane.showMessageDialog(this, getString("restart_success"), getString("info"), JOptionPane.INFORMATION_MESSAGE); } else { JOptionPane.showMessageDialog(this, getString("send_data_failed"), getString("error"), JOptionPane.ERROR_MESSAGE); } // 按钮视觉反馈 restartDeviceBtn.setBackground(Color.ORANGE); Timer timer = new Timer(500, e -> { restartDeviceBtn.setBackground(new Color(70, 130, 180)); }); timer.setRepeats(false); timer.start(); } /** * 恢复出厂设置 - 修复方法 */ private void resetFactory() { if (!serialService.isOpen()) { JOptionPane.showMessageDialog(this, getString("open_serial_first"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } // 恢复出厂设置命令 byte[] data = hexStringToByteArray(RESET_FACTORY_CMD); if (data == null) { JOptionPane.showMessageDialog(this, getString("invalid_hex_format"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } // 新增:在数据日志窗口显示发送的指令 if (dataLogPanel != null) { dataLogPanel.addLogData(data, "发送恢复出厂设置指令"); } boolean success = serialService.send(data); if (success) { JOptionPane.showMessageDialog(this, getString("reset_success"), getString("info"), JOptionPane.INFORMATION_MESSAGE); } else { JOptionPane.showMessageDialog(this, getString("send_data_failed"), getString("error"), JOptionPane.ERROR_MESSAGE); } // 按钮视觉反馈 resetFactoryBtn.setBackground(Color.RED); Timer timer = new Timer(500, e -> { resetFactoryBtn.setBackground(new Color(70, 130, 180)); }); timer.setRepeats(false); timer.start(); } private JPanel createControlPanel() { JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); // 使用国际化字符串创建标签 selectSerialLabel = new JLabel(getString("select.serial")); panel.add(selectSerialLabel); serialPortCombo = new JComboBox<>(); // 添加弹出菜单监听器,点击时刷新串口列表 serialPortCombo.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { refreshSerialPorts(); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} @Override public void popupMenuCanceled(PopupMenuEvent e) {} }); refreshSerialPorts(); // 初始刷新串口列表 panel.add(serialPortCombo); baudRateLabel = new JLabel(getString("baud.rate")); panel.add(baudRateLabel); baudRateCombo = new JComboBox<>(new String[]{"9600", "19200", "38400", "115200", "921600"}); baudRateCombo.setSelectedItem("115200"); panel.add(baudRateCombo); // 使用ButtonUtils创建蓝色样式按钮 openBtn = ButtonUtils.createBlueButton(getString("open")); openBtn.addActionListener(e -> toggleSerialPort()); panel.add(openBtn); return panel; } /** * 刷新串口列表 */ private void refreshSerialPorts() { String selectedPort = (String) serialPortCombo.getSelectedItem(); serialPortCombo.removeAllItems(); SerialPort[] ports = SerialPort.getCommPorts(); for (SerialPort port : ports) { serialPortCombo.addItem(port.getSystemPortName()); } // 尝试恢复之前的选择 if (selectedPort != null) { serialPortCombo.setSelectedItem(selectedPort); } else if (ports.length > 0) { serialPortCombo.setSelectedIndex(0); } } /** * 切换串口打开/关闭状态 */ private void toggleSerialPort() { if (isOpen) { // 关闭串口 closeSerialPort(); openBtn.setText(getString("open")); isOpen = false; JOptionPane.showMessageDialog(this, getString("serial.closed"), getString("info"), JOptionPane.INFORMATION_MESSAGE); } else { // 打开串口 if (openSerialPort()) { openBtn.setText(getString("close")); isOpen = true; JOptionPane.showMessageDialog(this, getString("serial.opened"), getString("info"), JOptionPane.INFORMATION_MESSAGE); } } } /** * 打开串口 * @return 是否成功打开 */ private boolean openSerialPort() { String portName = (String) serialPortCombo.getSelectedItem(); if (portName == null || portName.isEmpty()) { JOptionPane.showMessageDialog(this, getString("select.serial.first"), getString("error"), JOptionPane.ERROR_MESSAGE); return false; } int baudRate = Integer.parseInt((String) baudRateCombo.getSelectedItem()); boolean success = serialService.open(portName, baudRate); if (success) { // 设置数据接收回调,将数据发送到数据日志面板 serialService.startCapture(this::handleReceivedData); } else { JOptionPane.showMessageDialog(this, getString("open.serial.failed"), getString("error"), JOptionPane.ERROR_MESSAGE); } return success; } /** * 处理接收到的串口数据 */ private void handleReceivedData(byte[] data) { if (dataLogPanel != null && data != null && data.length > 0) { dataLogPanel.addLogData(data); } } /** * 关闭串口 */ private void closeSerialPort() { if (serialService != null) { serialService.close(); } } private JPanel createBaseParameterPanel() { JPanel panel = new JPanel(new BorderLayout()); baseParamPanel = new BaseParameterPanel(mainFrame); panel.add(baseParamPanel, BorderLayout.CENTER); return panel; } private JPanel createRightPanel() { JPanel panel = new JPanel(new BorderLayout()); panel.setBorder(null); // 移除面板边框 // 右侧选项卡 rightTabbedPane = new JTabbedPane(); // 创建各个功能面板 baseStationPanel = new BaseStationPanel(mainFrame); tagPanel = new TagPanel(mainFrame); antiCollisionPanel = new AntiCollisionPanel(mainFrame); upgradePanel = new UpgradePanel(mainFrame); rightTabbedPane.addTab(getString("base.station"), baseStationPanel); rightTabbedPane.addTab(getString("tag"), tagPanel); rightTabbedPane.addTab(getString("anti.collision"), antiCollisionPanel); rightTabbedPane.addTab(getString("upgrade"), upgradePanel); panel.add(rightTabbedPane, BorderLayout.CENTER); return panel; } private JPanel createBottomButtonPanel() { JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); // 使用ButtonUtils创建蓝色样式按钮 readParamsBtn = ButtonUtils.createBlueButton(getString("read.parameters")); saveParamsBtn = ButtonUtils.createBlueButton(getString("save.parameters")); restartDeviceBtn = ButtonUtils.createBlueButton(getString("restart.device")); resetFactoryBtn = ButtonUtils.createBlueButton(getString("reset.factory")); panel.add(readParamsBtn); panel.add(saveParamsBtn); panel.add(restartDeviceBtn); panel.add(resetFactoryBtn); return panel; } // 十六进制字符串转字节数组 private byte[] hexStringToByteArray(String s) { try { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); } return data; } catch (Exception e) { return null; } } // 字节数组转十六进制字符串 private String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X", b)); } return sb.toString(); } public void updateLanguage() { // 更新控制面板文本 selectSerialLabel.setText(getString("select.serial")); baudRateLabel.setText(getString("baud.rate")); openBtn.setText(isOpen ? getString("close") : getString("open")); // 更新底部按钮文本 readParamsBtn.setText(getString("read.parameters")); saveParamsBtn.setText(getString("save.parameters")); restartDeviceBtn.setText(getString("restart.device")); resetFactoryBtn.setText(getString("reset.factory")); // 更新选项卡标题 if (rightTabbedPane != null) { rightTabbedPane.setTitleAt(0, getString("base.station")); rightTabbedPane.setTitleAt(1, getString("tag")); rightTabbedPane.setTitleAt(2, getString("anti.collision")); rightTabbedPane.setTitleAt(3, getString("upgrade")); } // 更新各个功能面板的语言 if (baseParamPanel != null) { baseParamPanel.updateLanguage(); } if (baseStationPanel != null) { baseStationPanel.updateLanguage(); } if (tagPanel != null) { tagPanel.updateLanguage(); } if (antiCollisionPanel != null) { antiCollisionPanel.updateLanguage(); } if (upgradePanel != null) { upgradePanel.updateLanguage(); } revalidate(); repaint(); } private String getString(String key) { return mainFrame.getString(key); } /** * 设置数据日志面板引用 */ public void setDataLogPanel(DataLogPanel dataLogPanel) { this.dataLogPanel = dataLogPanel; } /** * 获取串口服务实例 * @return 串口服务实例 */ public SerialPortService getSerialService() { return serialService; } /** * 面板销毁时关闭串口 */ @Override protected void finalize() throws Throwable { closeSerialPort(); super.finalize(); } /** * 获取当前选中的面板索引 * @return 当前选中的面板索引 (0-基站, 1-标签, 2-防撞, 3-升级) */ public static int getCurrentSelectedPanelIndex() { if (rightTabbedPane == null) { return 0; // 默认基站面板 } return rightTabbedPane.getSelectedIndex(); } }