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<String> 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<byte[]> 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();
|
}
|
|
}
|