From 0e0e51fc63a865977d751271be28437e24dd6a99 Mon Sep 17 00:00:00 2001 From: 826220679@qq.com <826220679@qq.com> Date: 星期四, 07 八月 2025 23:53:37 +0800 Subject: [PATCH] 修改 --- lib/jSerialComm-2.10.4.jar | 0 src/Dell55aa/Dell55AA01.java | 5 src/window/NavigationTreeFactory.java | 1 lib/RXTXcomm.jar | 0 src/Dell55aa/Dell55AA12HighPerf.java | 180 +++++++ systemfile/logfile/openlog.txt | 120 +++++ /dev/null | 4 systemfile/Messages_en.properties | 44 + systemfile/Messages_zh.properties | 58 ++ src/publicsWay/UwbDataParser.java | 140 ++++++ src/window/ContentPanelFactory.java | 3 src/dell_system/SerialPortService.java | 165 +++++++ src/dell_system/SerialCommPanel.java | 586 +++++++++++++++++++++++++ src/publicsWay/JugeNumber.java | 67 ++ 14 files changed, 1,369 insertions(+), 4 deletions(-) diff --git a/lib/RXTXcomm.jar b/lib/RXTXcomm.jar new file mode 100644 index 0000000..e1e7503 --- /dev/null +++ b/lib/RXTXcomm.jar Binary files differ diff --git a/lib/jSerialComm-2.10.4.jar b/lib/jSerialComm-2.10.4.jar new file mode 100644 index 0000000..2a29395 --- /dev/null +++ b/lib/jSerialComm-2.10.4.jar Binary files differ diff --git a/src/Dell55aa/Dell55AA01.java b/src/Dell55aa/Dell55AA01.java new file mode 100644 index 0000000..4ca9bef --- /dev/null +++ b/src/Dell55aa/Dell55AA01.java @@ -0,0 +1,5 @@ +package Dell55aa; + +public class Dell55AA01 { + +} diff --git a/src/Dell55aa/Dell55AA12HighPerf.java b/src/Dell55aa/Dell55AA12HighPerf.java new file mode 100644 index 0000000..5a754a9 --- /dev/null +++ b/src/Dell55aa/Dell55AA12HighPerf.java @@ -0,0 +1,180 @@ +package Dell55aa; + +public class Dell55AA12HighPerf { // 高性能解析类 + + // 常量定义(避免重复创建) + private static final String HEADER = "55AA12"; // 包头常量 + private static final int MIN_LENGTH = 34; // 最小有效长度 + private static final ThreadLocal<ParseResult> RESULT_CACHE = // 线程本地结果缓存 + ThreadLocal.withInitial(ParseResult::new); + private static final ThreadLocal<char[]> CHAR_BUF_CACHE = // 字符缓冲区缓存 + ThreadLocal.withInitial(() -> new char[256]); + + // 十六进制字符转换表(避免重复计算) + private static final int[] HEX_VALUES = new int[128]; + static { + for (int i = 0; i < HEX_VALUES.length; i++) { + char c = (char) i; + if (c >= '0' && c <= '9') HEX_VALUES[i] = c - '0'; + else if (c >= 'A' && c <= 'F') HEX_VALUES[i] = 10 + (c - 'A'); + else if (c >= 'a' && c <= 'f') HEX_VALUES[i] = 10 + (c - 'a'); + else HEX_VALUES[i] = -1; // 非法字符标记 + } + } + + // 解析结果复用类(对象池模式) + public static class ParseResult { + public int tagId; + public int sequenceNum; + public int power; + public int vibrationState; + public boolean tagRemoved; + public boolean isSleeping; + public boolean isStatic; + public boolean sosButtonPressed; + public int tagHeight; + public int anchorCount; + public int[] anchorIds = new int[0]; + public int[] distances = new int[0]; + public int[] anchorPowers = new int[0]; + public int[] signalStrengths1 = new int[0]; + public int[] signalStrengths2 = new int[0]; + + // 重置方法(避免重新创建数组) + public void reset() { + tagId = 0; + sequenceNum = 0; + power = 0; + vibrationState = 0; + tagRemoved = false; + isSleeping = false; + isStatic = false; + sosButtonPressed = false; + tagHeight = 0; + anchorCount = 0; + // 保留数组,仅重置长度 + } + } + + /** + * 高性能解析方法 + * @param message 原始16进制消息 + * @return 解析结果对象(线程内复用) + */ + public static ParseResult parse(String message) { + // 快速长度校验 + if (message == null || message.length() < MIN_LENGTH) { + return null; // 快速失败 + } + + // 包头检查(避免创建子字符串) + if (!(message.charAt(0) == '5' && + message.charAt(1) == '5' && + message.charAt(2) == 'A' && + message.charAt(3) == 'A' && + message.charAt(4) == '1' && + message.charAt(5) == '2')) { + return null; // 包头无效 + } + + // 从线程缓存获取结果对象 + ParseResult result = RESULT_CACHE.get(); + result.reset(); // 重置对象状态 + + // 直接操作字符数组(避免字符串操作) + char[] chars = CHAR_BUF_CACHE.get(); + message.getChars(0, Math.min(message.length(), chars.length), chars, 0); + + // 解析数据长度(直接计算) + int dataLength = (fastHexToByte(chars[6], chars[7]) * 2) + 8; + if (message.length() != dataLength) { + return null; // 长度不匹配 + } + + // 解析标签信息(无临时对象创建) + parseTagInfo(chars, result); + + // 解析基站信息(数组复用) + parseAnchorInfo(chars, result); + + return result; + } + + /** + * 标签信息解析(无对象创建) + */ + private static void parseTagInfo(char[] chars, ParseResult result) { + // 标签ID(直接计算) + result.tagId = (fastHexToByte(chars[10], chars[11]) << 8) | + fastHexToByte(chars[8], chars[9]); + + // 包序列号(直接计算) + result.sequenceNum = (fastHexToByte(chars[14], chars[15]) << 8) | + fastHexToByte(chars[12], chars[13]); + + // 电量(单字节转换) + result.power = fastHexToByte(chars[16], chars[17]); + + // 按键状态(位运算代替字符串操作) + int buttonState = fastHexToByte(chars[18], chars[19]); + result.vibrationState = (buttonState >> 5) & 1; // 第2位 + result.tagRemoved = ((buttonState >> 3) & 1) == 1; // 第4位 + result.isSleeping = ((buttonState >> 2) & 1) == 1; // 第5位 + result.isStatic = ((buttonState >> 1) & 1) == 1; // 第6位 + result.sosButtonPressed = (buttonState & 1) == 1; // 第7位 + + // 标签高度(直接计算) + result.tagHeight = (fastHexToByte(chars[22], chars[23]) << 8) | + fastHexToByte(chars[20], chars[21]); + } + + /** + * 基站信息解析(数组复用) + */ + private static void parseAnchorInfo(char[] chars, ParseResult result) { + // 基站数量 + result.anchorCount = fastHexToByte(chars[32], chars[33]); + if (result.anchorCount == 0) return; + + // 数组复用检查(避免重复创建) + if (result.anchorIds.length < result.anchorCount) { + result.anchorIds = new int[result.anchorCount]; + result.distances = new int[result.anchorCount]; + result.anchorPowers = new int[result.anchorCount]; + result.signalStrengths1 = new int[result.anchorCount]; + result.signalStrengths2 = new int[result.anchorCount]; + } + + // 基站信息解析(直接索引计算) + int baseIndex = 34; + int powerIndex = 34 + result.anchorCount * 4; + + for (int i = 0; i < result.anchorCount; i++) { + // 基站ID(小端序) + int idLow = fastHexToByte(chars[baseIndex], chars[baseIndex+1]); + int idHigh = fastHexToByte(chars[baseIndex+2], chars[baseIndex+3]); + result.anchorIds[i] = (idHigh << 8) | idLow; + + // 基站距离 + int distLow = fastHexToByte(chars[baseIndex+4], chars[baseIndex+5]); + int distHigh = fastHexToByte(chars[baseIndex+6], chars[baseIndex+7]); + result.distances[i] = (distHigh << 8) | distLow; + + // 基站电量 + result.anchorPowers[i] = fastHexToByte(chars[powerIndex], chars[powerIndex+1]); + + baseIndex += 8; // 每个基站占用8字符 + powerIndex += 2; // 每个电量占用2字符 + } + } + + /** + * 快速十六进制转字节(查表法) + */ + private static int fastHexToByte(char c1, char c2) { + int high = (c1 < 128) ? HEX_VALUES[c1] : -1; + int low = (c2 < 128) ? HEX_VALUES[c2] : -1; + if (high < 0 || low < 0) return 0; // 无效字符处理 + return (high << 4) | low; + } +} \ No newline at end of file diff --git a/src/dell_system/SerialCommPanel.java b/src/dell_system/SerialCommPanel.java new file mode 100644 index 0000000..2ab154d --- /dev/null +++ b/src/dell_system/SerialCommPanel.java @@ -0,0 +1,586 @@ +package dell_system; +import com.fazecast.jSerialComm.SerialPort; +import Dell55aa.Dell55AA12HighPerf; +import Dell55aa.Dell55AA12HighPerf.ParseResult; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.ResourceBundle; + +public class SerialCommPanel extends JPanel { + + private static final long serialVersionUID = 1L; + private final ResourceBundle messages; + private final SerialPortService serialService = new SerialPortService(); + + // 新增字段 + private int packetCounter = 0; + private JLabel lblParseStatus; + private JCheckBox chkEnableParsing; + private JLabel lblPacketCount; // 新增:数据包计数标签 + + // UI 组件 + private JComboBox<String> cbPorts; + private JComboBox<String> cbBaudRate; + private JCheckBox chkHexDisplay; + private JCheckBox chkTimestamp; + private JCheckBox chkAppendNewline; + private JCheckBox chkHexSend; + private JCheckBox chkTimedSend; + private JTextField txtInterval; + private JButton btnOpenSerial; + private JButton btnStart; + private JButton btnPause; + private JButton btnClear; + private JTextField txtSendData; + private JButton btnSend; + private JTextArea txtRawData; + private JTextArea txtParsedData; + private JScrollPane rawScrollPane; + private JScrollPane parsedScrollPane; + + private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); + + public SerialCommPanel(ResourceBundle messages) { + this.messages = messages; + initUI(); + } + + /* ================= UI 初始化 ================= */ + private void initUI() { + setLayout(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5, 10, 5, 10); + gbc.anchor = GridBagConstraints.WEST; + gbc.fill = GridBagConstraints.HORIZONTAL; + setBackground(new Color(240, 245, 249)); + + /* ===== 串口选择和波特率 ===== */ + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = 1; + gbc.weightx = 0.3; + JPanel portPanel = new JPanel(new BorderLayout(5, 0)); + portPanel.setBackground(new Color(240, 245, 249)); + JLabel lblPort = new JLabel(messages.getString("SERIAL_PORT")); + lblPort.setFont(new Font("宋体", Font.BOLD, 12)); + portPanel.add(lblPort, BorderLayout.WEST); + + cbPorts = new JComboBox<>(); + cbPorts.setBackground(new Color(200, 255, 200)); + scanSerialPorts(); + cbPorts.addPopupMenuListener(new PopupMenuListener() { + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + scanSerialPorts(); + } + + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + } + + @Override + public void popupMenuCanceled(PopupMenuEvent e) { + } + }); + portPanel.add(cbPorts, BorderLayout.CENTER); + add(portPanel, gbc); + + gbc.gridx++; + JPanel baudPanel = new JPanel(new BorderLayout(5, 0)); + baudPanel.setBackground(new Color(240, 245, 249)); + JLabel lblBaud = new JLabel(messages.getString("BAUD_RATE")); + lblBaud.setFont(new Font("宋体", Font.BOLD, 12)); + baudPanel.add(lblBaud, BorderLayout.WEST); + + cbBaudRate = new JComboBox<>(new String[]{ + "19200", "38400", "57600", "115200", + "230400", "460800", "921600" + }); + cbBaudRate.setBackground(new Color(255, 200, 255)); + cbBaudRate.setSelectedItem("115200"); + baudPanel.add(cbBaudRate, BorderLayout.CENTER); + add(baudPanel, gbc); + + gbc.gridx++; + btnOpenSerial = createStyledButton(messages.getString("OPEN_SERIAL"), new Color(70, 130, 180)); + btnOpenSerial.addActionListener(e -> toggleSerialPort()); + add(btnOpenSerial, gbc); + + /* ===== 原始数据显示区域 ===== */ + gbc.gridx = 0; + gbc.gridy++; + gbc.gridwidth = 3; + gbc.weighty = 0.5; + gbc.fill = GridBagConstraints.BOTH; + txtRawData = new JTextArea(); + txtRawData.setFont(new Font("Monospaced", Font.PLAIN, 12)); + txtRawData.setEditable(false); + txtRawData.setBackground(new Color(255, 200, 200)); + txtRawData.setLineWrap(true); + txtRawData.setWrapStyleWord(false); + rawScrollPane = new JScrollPane(txtRawData); + rawScrollPane.setBorder(BorderFactory.createTitledBorder( + BorderFactory.createLineBorder(Color.DARK_GRAY), + messages.getString("RAW_DATA_WINDOW"), + TitledBorder.LEFT, TitledBorder.TOP, + new Font("宋体", Font.BOLD, 12), Color.BLACK)); + add(rawScrollPane, gbc); + + /* ===== 解析数据显示区域 ===== */ + gbc.gridy++; + txtParsedData = new JTextArea(); + txtParsedData.setFont(new Font("Monospaced", Font.PLAIN, 12)); + txtParsedData.setEditable(false); + txtParsedData.setBackground(new Color(255, 255, 200)); + txtParsedData.setLineWrap(true); + txtParsedData.setWrapStyleWord(false); + parsedScrollPane = new JScrollPane(txtParsedData); + parsedScrollPane.setBorder(BorderFactory.createTitledBorder( + BorderFactory.createLineBorder(Color.DARK_GRAY), + messages.getString("PARSED_DATA_WINDOW"), + TitledBorder.LEFT, TitledBorder.TOP, + new Font("宋体", Font.BOLD, 12), Color.BLACK)); + add(parsedScrollPane, gbc); + + /* ===== 为解析窗口添加右键菜单 ===== */ + JPopupMenu parsedPopup = new JPopupMenu(); + JMenuItem clearItem = new JMenuItem(messages.getString("CLEAR")); + JMenuItem exportItem = new JMenuItem(messages.getString("EXPORT")); + + clearItem.addActionListener(e -> txtParsedData.setText("")); + exportItem.addActionListener(e -> exportParsedData()); + + parsedPopup.add(clearItem); + parsedPopup.add(exportItem); + txtParsedData.setComponentPopupMenu(parsedPopup); + + /* ===== 控制和显示选项 ===== */ + gbc.gridy++; + gbc.weighty = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + JPanel controlPanel = new JPanel(new BorderLayout(10, 0)); + controlPanel.setBackground(new Color(240, 245, 249)); + + // 左侧控制按钮 + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5)); + buttonPanel.setBackground(new Color(240, 245, 249)); + + btnStart = createStyledButton(messages.getString("START"), new Color(70, 130, 180)); + btnPause = createStyledButton(messages.getString("PAUSE"), new Color(218, 165, 32)); + btnClear = createStyledButton(messages.getString("CLEAR"), new Color(205, 92, 92)); + + btnStart.setEnabled(true); + btnPause.setEnabled(false); + + btnStart.addActionListener(e -> startCapture()); + btnPause.addActionListener(e -> pauseCapture()); + btnClear.addActionListener(e -> clearDisplay()); + + buttonPanel.add(btnStart); + buttonPanel.add(btnPause); + buttonPanel.add(btnClear); + + // 新增:数据包计数标签 + lblPacketCount = new JLabel(String.format(messages.getString("packet.count.format"), 0)); + lblPacketCount.setFont(new Font("宋体", Font.BOLD, 12)); + lblPacketCount.setForeground(new Color(0, 100, 0)); // 深绿色 + buttonPanel.add(lblPacketCount); + + controlPanel.add(buttonPanel, BorderLayout.WEST); + + // 右侧显示选项 + JPanel checkboxPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5)); + checkboxPanel.setBackground(new Color(240, 245, 249)); + + chkHexDisplay = createStyledCheckbox(messages.getString("HEX_DISPLAY")); + chkTimestamp = createStyledCheckbox(messages.getString("TIMESTAMP")); + chkAppendNewline = createStyledCheckbox(messages.getString("APPEND_NEWLINE")); + chkHexSend = createStyledCheckbox(messages.getString("HEX_SEND")); + chkTimedSend = createStyledCheckbox(messages.getString("TIMED_SEND")); + chkHexDisplay.setSelected(true); + chkTimestamp.setSelected(true); + chkAppendNewline.setSelected(true); + + txtInterval = new JTextField("1000", 5); + txtInterval.setEnabled(false); + txtInterval.setFont(new Font("宋体", Font.PLAIN, 12)); + txtInterval.setBackground(Color.WHITE); + chkTimedSend.addActionListener(e -> txtInterval.setEnabled(chkTimedSend.isSelected())); + + // 新增解析控制选项 + chkEnableParsing = createStyledCheckbox(messages.getString("ENABLE_PARSING")); + chkEnableParsing.setSelected(true); + + // 删除解析器下拉框及其标签 + checkboxPanel.add(chkHexDisplay); + checkboxPanel.add(chkTimestamp); + checkboxPanel.add(chkAppendNewline); + checkboxPanel.add(chkHexSend); + checkboxPanel.add(chkTimedSend); + checkboxPanel.add(new JLabel(messages.getString("INTERVAL_MS"))); + checkboxPanel.add(txtInterval); + checkboxPanel.add(chkEnableParsing); + controlPanel.add(checkboxPanel, BorderLayout.EAST); + + // 新增解析状态指示器 + JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + statusPanel.setBackground(new Color(240, 245, 249)); + lblParseStatus = new JLabel(messages.getString("parser.ready")); + lblParseStatus.setFont(new Font("宋体", Font.PLAIN, 12)); + lblParseStatus.setForeground(Color.BLUE); + statusPanel.add(lblParseStatus); + controlPanel.add(statusPanel, BorderLayout.CENTER); + + add(controlPanel, gbc); + + /* ===== 发送区域 ===== */ + gbc.gridy++; + JPanel sendPanel = new JPanel(new BorderLayout(10, 5)); + sendPanel.setBackground(new Color(240, 245, 249)); + + txtSendData = new JTextField(); + txtSendData.setBackground(new Color(200, 200, 255)); + txtSendData.setFont(new Font("宋体", Font.PLAIN, 12)); + + btnSend = createStyledButton(messages.getString("SEND"), new Color(60, 179, 113)); + btnSend.addActionListener(e -> sendData()); + + sendPanel.add(new JLabel(messages.getString("SEND_DATA")), BorderLayout.WEST); + sendPanel.add(txtSendData, BorderLayout.CENTER); + sendPanel.add(btnSend, BorderLayout.EAST); + add(sendPanel, gbc); + + addNotify(); + } + + /* ================= 扫描串口列表 ================= */ + private void scanSerialPorts() { + cbPorts.removeAllItems(); + SerialPort[] ports = SerialPort.getCommPorts(); + if (ports.length == 0) { + cbPorts.addItem("No port found"); + cbPorts.setEnabled(false); + return; + } + for (SerialPort p : ports) { + String item = p.getSystemPortName(); + String desc = p.getPortDescription(); + if (desc != null && !desc.trim().isEmpty()) { + item += " (" + desc + ")"; + } + cbPorts.addItem(item); + } + cbPorts.setEnabled(true); + } + + /* ================= 打开/关闭串口 ================= */ + private void toggleSerialPort() { + if (serialService.isOpen()) { + serialService.close(); + btnOpenSerial.setText(messages.getString("OPEN_SERIAL")); + btnStart.setEnabled(true); + btnPause.setEnabled(false); + } else { + String selected = (String) cbPorts.getSelectedItem(); + if (selected == null || selected.startsWith("No port")) { + JOptionPane.showMessageDialog(this, + messages.getString("SELECT_PORT_ERROR"), + messages.getString("ERROR"), JOptionPane.ERROR_MESSAGE); + return; + } + String portName = selected.split(" ")[0]; + int baud = Integer.parseInt((String) cbBaudRate.getSelectedItem()); + if (serialService.open(portName, baud)) { + btnOpenSerial.setText(messages.getString("CLOSE_SERIAL")); + startCapture(); + } else { + JOptionPane.showMessageDialog(this, + messages.getString("OPEN_PORT_ERROR"), + messages.getString("ERROR"), JOptionPane.ERROR_MESSAGE); + } + } + } + + /* ================= 数据接收控制 ================= */ + private void startCapture() { + if (!serialService.isOpen()) return; + serialService.startCapture(this::appendRawData); + btnStart.setEnabled(false); + btnPause.setEnabled(true); + } + + private void pauseCapture() { + serialService.setPaused(!serialService.isPaused()); + btnPause.setText(serialService.isPaused() + ? messages.getString("RESUME") + : messages.getString("PAUSE")); + } + + /* ================= 解析数据显示 ================= */ + private void appendParsedData(byte[] data) { + if (!chkEnableParsing.isSelected()) return; + + SwingUtilities.invokeLater(() -> { + packetCounter++; + lblPacketCount.setText(String.format(messages.getString("packet.count.format"), packetCounter)); // 更新计数标签 + + try { + // 将字节数据转换为十六进制字符串 + String hexData = bytesToHex(data).toUpperCase(); + // 使用Dell55AA12HighPerf解析 + ParseResult result = Dell55AA12HighPerf.parse(hexData); + + if (result != null) { + // 构建状态字符串 + String buttonStatus = result.sosButtonPressed ? messages.getString("yes") : messages.getString("no"); + String staticStatus = result.isStatic ? messages.getString("yes") : messages.getString("no"); + String sleepStatus = result.isSleeping ? messages.getString("yes") : messages.getString("no"); + String vibrationStatus = (result.vibrationState == 1) ? messages.getString("on") : messages.getString("off"); + String uwbStatus = result.tagRemoved ? messages.getString("off") : messages.getString("on"); + + // 构建基站信息 + StringBuilder anchorIds = new StringBuilder(); + StringBuilder distances = new StringBuilder(); + StringBuilder anchorPowers = new StringBuilder(); + + for (int i = 0; i < result.anchorCount; i++) { + if (i > 0) { + anchorIds.append(","); + distances.append(","); + anchorPowers.append(","); + } + anchorIds.append(result.anchorIds[i]); + distances.append(result.distances[i]); + anchorPowers.append(result.anchorPowers[i]); + } + + // 格式化输出 + StringBuilder parsedOutput = new StringBuilder(); + + // 添加时间戳(如果勾选) + if (chkTimestamp.isSelected()) { + parsedOutput.append("[").append(sdf.format(new Date())).append("]\n"); + } + + parsedOutput.append(String.format( + "%s: %d\n%s: %d\n%s: %d%%\n%s: %s[%s], %s[%s], %s[%s], %s[%s], %s[%s]\n%s: %d\n%s: %d\n%s: (%s)\n%s: (%s)\n%s: (%s)\n\n", + messages.getString("label.id"), result.tagId, + messages.getString("label.sequence"), result.sequenceNum, + messages.getString("label.power"), result.power, + messages.getString("label.status"), + messages.getString("status.button"), buttonStatus, + messages.getString("status.static"), staticStatus, + messages.getString("status.sleeping"), sleepStatus, + messages.getString("status.vibration"), vibrationStatus, + messages.getString("status.uwb_switch"), uwbStatus, + messages.getString("label.tag_height"), result.tagHeight, + messages.getString("label.anchor_count"), result.anchorCount, + messages.getString("label.anchor_ids"), anchorIds.toString(), + messages.getString("label.distances"), distances.toString(), + messages.getString("label.anchor_powers"), anchorPowers.toString() + )); + + txtParsedData.append(parsedOutput.toString()); + txtParsedData.setCaretPosition(txtParsedData.getDocument().getLength()); + lblParseStatus.setText(String.format("%s (Packets: %d)", messages.getString("parser.ready"), packetCounter)); + } else { + StringBuilder invalidMsg = new StringBuilder(); + // 添加时间戳(如果勾选) + if (chkTimestamp.isSelected()) { + + invalidMsg.append("[").append(sdf.format(new Date())).append("]\n"); + } + invalidMsg.append(String.format("[Packet #%d] Not a valid 55AA12 packet\n\n", packetCounter)); + + txtParsedData.append(invalidMsg.toString()); + lblParseStatus.setText(String.format("Parser: Invalid (Packets: %d)", packetCounter)); + } + } catch (Exception e) { + StringBuilder errorMsg = new StringBuilder(); + // 添加时间戳(如果勾选) + if (chkTimestamp.isSelected()) { + errorMsg.append("[").append(sdf.format(new Date())).append("]\n"); + } + errorMsg.append(String.format("[Packet #%d] Parse error: %s\n\n", + packetCounter, e.getMessage())); + + txtParsedData.append(errorMsg.toString()); + lblParseStatus.setText(String.format("Parser: Error (Packets: %d)", packetCounter)); + } + }); + } + + /* ================= UI 更新 ================= */ + private void appendRawData(byte[] bytes) { + SwingUtilities.invokeLater(() -> { + StringBuilder sb = new StringBuilder(); + + if (chkTimestamp.isSelected()) { + sb.append("[").append(sdf.format(new Date())).append("] "); + } + + if (chkHexDisplay.isSelected()) { + for (byte b : bytes) { + sb.append(String.format("%02X ", b)); + } + } else { + for (byte b : bytes) { + if (b != 0) sb.append((char) b); + } + } + + sb.append("\n"); + txtRawData.append(sb.toString()); + txtRawData.setCaretPosition(txtRawData.getDocument().getLength()); + + // 触发解析 + appendParsedData(bytes); + }); + } + + private void sendData() { + String data = txtSendData.getText().trim(); + if (data.isEmpty()) { + JOptionPane.showMessageDialog(this, + messages.getString("EMPTY_SEND_DATA"), + messages.getString("WARNING"), JOptionPane.WARNING_MESSAGE); + return; + } + + byte[] sendBytes; + + if (chkHexSend.isSelected()) { + try { + sendBytes = hexStringToBytes(data); + if (sendBytes == null) { + throw new IllegalArgumentException("HEX格式错误"); + } + } catch (Exception ex) { + JOptionPane.showMessageDialog(this, + "HEX格式错误,请输入有效的十六进制数据(如:01 0A FF)", + "格式错误", JOptionPane.ERROR_MESSAGE); + return; + } + } else { + sendBytes = data.getBytes(); + if (chkAppendNewline.isSelected()) { + String newline = "\r\n"; + byte[] newlineBytes = newline.getBytes(); + byte[] combined = new byte[sendBytes.length + newlineBytes.length]; + System.arraycopy(sendBytes, 0, combined, 0, sendBytes.length); + System.arraycopy(newlineBytes, 0, combined, sendBytes.length, newlineBytes.length); + sendBytes = combined; + } + } + + if (!serialService.send(sendBytes)) { + JOptionPane.showMessageDialog(this, + messages.getString("SEND_ERROR"), + messages.getString("ERROR"), JOptionPane.ERROR_MESSAGE); + } + } + + /* ================= 导出解析数据 ================= */ + private void exportParsedData() { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle(messages.getString("EXPORT_PARSED_DATA")); + if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { + try (PrintWriter writer = new PrintWriter(fileChooser.getSelectedFile())) { + writer.write(txtParsedData.getText()); + JOptionPane.showMessageDialog(this, + messages.getString("EXPORT_SUCCESS"), + messages.getString("INFO"), JOptionPane.INFORMATION_MESSAGE); + } catch (Exception ex) { + JOptionPane.showMessageDialog(this, + messages.getString("EXPORT_FAILED") + ": " + ex.getMessage(), + messages.getString("ERROR"), JOptionPane.ERROR_MESSAGE); + } + } + } + + /* ================= 辅助方法 ================= */ + private byte[] hexStringToBytes(String hexString) { + if (hexString == null || hexString.trim().isEmpty()) { + return null; + } + + hexString = hexString.replaceAll("\\s+", ""); + + if (hexString.length() % 2 != 0) { + return null; + } + + try { + byte[] result = new byte[hexString.length() / 2]; + for (int i = 0; i < result.length; i++) { + int index = i * 2; + String byteStr = hexString.substring(index, index + 2); + result[i] = (byte) Integer.parseInt(byteStr, 16); + } + return result; + } catch (NumberFormatException e) { + return null; + } + } + + private JButton createStyledButton(String text, Color bg) { + JButton b = new JButton(text); + b.setFont(new Font("宋体", Font.BOLD, 12)); + b.setBackground(bg); + b.setForeground(Color.WHITE); + b.setFocusPainted(false); + b.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createLineBorder(bg.darker(), 1), + BorderFactory.createEmptyBorder(5, 15, 5, 15))); + return b; + } + + private JCheckBox createStyledCheckbox(String text) { + JCheckBox c = new JCheckBox(text); + c.setFont(new Font("宋体", Font.PLAIN, 12)); + c.setBackground(new Color(240, 245, 249)); + c.setForeground(new Color(70, 70, 70)); + return c; + } + + /* ================= 窗口关闭处理 ================= */ + @Override + public void addNotify() { + super.addNotify(); + java.awt.Window w = SwingUtilities.getWindowAncestor(this); + if (w != null) { + w.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + serialService.close(); + } + }); + } + } + + // 新增辅助方法:字节数组转十六进制字符串 + private String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02X", b)); + } + return sb.toString(); + } + + // 修改clearDisplay方法 + private void clearDisplay() { + txtRawData.setText(""); + txtParsedData.setText(""); + packetCounter = 0; + lblPacketCount.setText(String.format(messages.getString("packet.count.format"), 0)); + lblParseStatus.setText(messages.getString("parser.ready")); + } +} \ No newline at end of file diff --git a/src/dell_system/SerialPortService.java b/src/dell_system/SerialPortService.java new file mode 100644 index 0000000..c77592d --- /dev/null +++ b/src/dell_system/SerialPortService.java @@ -0,0 +1,165 @@ +// 声明包名 dell_system +package dell_system; + +// 导入串口通信库 +import com.fazecast.jSerialComm.SerialPort; +// 导入 Java 函数式接口 Consumer,用于数据接收回调 +import java.util.function.Consumer; +// 导入字节数组输出流 +import java.io.ByteArrayOutputStream; + +/** + * 串口服务类 + * 负责串口的打开、关闭、数据收发 + */ +public class SerialPortService { + + // 串口对象,用于与硬件通信 + private SerialPort port; + // 标记是否正在捕获数据(线程运行中) + private volatile boolean capturing = false; + // 标记是否暂停接收数据 + private volatile boolean paused = false; + + // 数据读取线程 + private Thread readerThread; + + /** + * 打开串口 + * @param portName 串口名称(如 COM3) + * @param baud 波特率(如 9600) + * @return 是否成功打开 + */ + public boolean open(String portName, int baud) { + // 如果串口已打开,直接返回成功 + if (port != null && port.isOpen()) { + return true; + } + + // 根据名称获取串口实例 + port = SerialPort.getCommPort(portName); + // 设置串口参数:波特率、数据位8、停止位1、无校验位 + port.setComPortParameters(baud, 8, 1, SerialPort.NO_PARITY); + // 修改为半阻塞模式,读超时1ms + port.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1, 0); + + // 打开串口并返回结果 + return port.openPort(); + } + + /** + * 关闭串口 + */ + public void close() { + // 先停止数据接收线程 + stopCapture(); + // 如果串口已打开,关闭它 + if (port != null && port.isOpen()) { + port.closePort(); + } + // 释放串口引用 + port = null; + } + + /** + * 启动数据接收线程 + * @param onReceived 数据接收回调函数,收到数据时调用 + */ + public void startCapture(Consumer<byte[]> onReceived) { + if (capturing || port == null || !port.isOpen()) return; + capturing = true; + paused = false; + + readerThread = new Thread(() -> { + // 创建数据缓冲区 + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + // 最后收到数据的时间戳 + long lastReceivedTime = 0; + // 读取缓冲区 + byte[] readBuffer = new byte[200]; + + while (capturing && port.isOpen()) { + // 处理暂停状态 + if (paused) { + buffer.reset(); // 清空累积数据 + // 清空串口接收缓冲区(读取并丢弃) + int len; + do { + len = port.readBytes(readBuffer, readBuffer.length); + } while (len > 0); + // 降低暂停状态下的CPU占用 + try { Thread.sleep(100); } catch (InterruptedException ignore) {} + continue; + } + + // 1. 检查超时并发送累积数据 + long currentTime = System.currentTimeMillis(); + if (buffer.size() > 0 && (currentTime - lastReceivedTime) >= 20) { + onReceived.accept(buffer.toByteArray()); + buffer.reset(); + } + + // 2. 读取新数据 + int len = port.readBytes(readBuffer, readBuffer.length); + currentTime = System.currentTimeMillis(); // 更新当前时间 + + if (len > 0) { + // 写入缓冲区并更新时间戳 + buffer.write(readBuffer, 0, len); + lastReceivedTime = currentTime; + } + + // 3. 降低CPU占用:无数据且缓冲区空时短暂休眠 + if (len <= 0 && buffer.size() == 0) { + try { Thread.sleep(1); } catch (InterruptedException ignore) {} + } + } + + // 线程结束前发送剩余数据 + if (buffer.size() > 0) { + onReceived.accept(buffer.toByteArray()); + } + }); + readerThread.setDaemon(true); + readerThread.start(); + } + + /** + * 停止数据接收线程 + */ + public void stopCapture() { + // 设置捕获标志为 false,通知线程退出 + capturing = false; + // 如果线程存在,等待最多500ms确保线程结束 + if (readerThread != null) { + try { readerThread.join(500); } catch (InterruptedException ignore) {} + // 清空线程引用 + readerThread = null; + } + } + + // 设置暂停状态 + public void setPaused(boolean paused) { + this.paused = paused; + } + + // 获取当前是否暂停 + public boolean isPaused() { + return paused; + } + + // 判断串口是否已打开 + public boolean isOpen() { + return port != null && port.isOpen(); + } + + /** + * 发送数据 + * @param data 要发送的字节数组 + * @return 是否成功发送 + */ + public boolean send(byte[] data) { + // 如果串口已初始化且已打开,发送数据并返回结果 + return port != null && port.isOpen() && port.writeBytes(data, data.length) > 0; + } +} \ No newline at end of file diff --git a/src/publicsWay/JugeNumber.java b/src/publicsWay/JugeNumber.java new file mode 100644 index 0000000..56fa9cb --- /dev/null +++ b/src/publicsWay/JugeNumber.java @@ -0,0 +1,67 @@ +package publicsWay; +import java.util.regex.Pattern; +public final class JugeNumber { // 添加final防止继承 + // 使用final修饰正则常量 + private static final String DIGIT_REGEX = "\\d+"; // 纯数字正则 + private static final String CONTAIN_DIGIT_REGEX = ".*\\d.*"; // 含数字正则 + private static final String LETTER_REGEX = "[a-zA-Z]+"; // 纯字母 + private static final String CONTAIN_LETTER_REGEX = ".*[a-zA-Z].*"; // 含字母 + private static final String CHINESE_REGEX = "^[\u4e00-\u9fa5]+$"; // 纯中文正则 + private static final String LETTER_DIGIT_REGEX = "^[a-zA-Z0-9]+$"; // 仅含字母数字 + private static final String CHINESE_LETTER_REGEX = "^[\u4e00-\u9fa5a-zA-Z]+$"; // 中文+字母 + private static final String CHINESE_LETTER_DIGIT_REGEX = "^[\u4e00-\u9fa5a-zA-Z0-9]+$"; // 中文+字母+数字 + + // 方法名和逻辑 + public static boolean isValidInteger(String num, int maxLength) { // 功能明确的方法名 + return isInteger(num) && num.length() <= maxLength; // 合并条件判断 + } + + // 预编译正则提高性能 + private static final Pattern INTEGER_PATTERN = Pattern.compile("^[-+]?\\d+$"); // 预编译整数正则 + public static boolean isInteger(String str) { + return str != null && INTEGER_PATTERN.matcher(str).matches(); // 添加null检查 + } + + // 简化正则调用 + public static boolean isLetterDigit(String str) { + return str != null && str.matches(LETTER_DIGIT_REGEX); // 添加null检查 + } + + // 中文检测 + public static boolean isChinese(String con) { + return con != null && con.matches(CHINESE_REGEX); // 使用完整字符串匹配 + } + + // 添加null检查 + public static boolean isLetterDigitOrChinese(String str) { + return str != null && str.matches(CHINESE_LETTER_DIGIT_REGEX); // 空安全检测 + } + + // 合并正则检测 + public static boolean checkChineseLetter(String str) { + return str != null && str.matches(CHINESE_LETTER_REGEX); // 直接使用正则匹配 + } + + // 标点检测逻辑 + public static boolean checkPunctuation(String input) { + if (input == null) return false; // 空值处理 + return input.length() != input.replaceAll("\\p{P}", "").length(); // 直接返回比较结果 + } + + // 简化方法实现 + public static boolean isDigit(String str) { + return str != null && str.matches(DIGIT_REGEX); // 空安全检测 + } + + public static boolean isLetter(String str) { + return str != null && str.matches(LETTER_REGEX); // 空安全检测 + } + + public static boolean hasDigit(String str) { + return str != null && str.matches(CONTAIN_DIGIT_REGEX); // 空安全检测 + } + + public static boolean hasLetter(String str) { + return str != null && str.matches(CONTAIN_LETTER_REGEX); // 空安全检测 + } +} \ No newline at end of file diff --git a/src/publicsWay/UwbDataParser.java b/src/publicsWay/UwbDataParser.java new file mode 100644 index 0000000..af69f73 --- /dev/null +++ b/src/publicsWay/UwbDataParser.java @@ -0,0 +1,140 @@ +// UwbDataParser.java +package publicsWay; +import java.util.ArrayList; +import java.util.List; + +public class UwbDataParser { + private byte[] buffer = new byte[4096]; + private int bufferLength = 0; + // 添加新的parse方法 + public String parse(byte[] data) { + // 添加数据到缓冲区 + appendData(data, data.length); + + // 解析数据包 + List<DataPacket> packets = parsePackets(); + + if (packets.isEmpty()) { + return "No complete packet found in data"; + } + + StringBuilder result = new StringBuilder(); + for (DataPacket packet : packets) { + result.append(packet.toString()).append("\n"); + } + return result.toString(); + } + + public void appendData(byte[] newData, int length) { + if (bufferLength + length > buffer.length) { + byte[] newBuffer = new byte[bufferLength + length]; + System.arraycopy(buffer, 0, newBuffer, 0, bufferLength); + buffer = newBuffer; + } + System.arraycopy(newData, 0, buffer, bufferLength, length); + bufferLength += length; + } + + public void clearBuffer() { + bufferLength = 0; + } + + public List<DataPacket> parsePackets() { + List<DataPacket> packets = new ArrayList<>(); + int index = 0; + + while (index <= bufferLength - 4) { + if (buffer[index] == 0x55 && (buffer[index + 1] & 0xFF) == 0xAA) { + int dataType = buffer[index + 2] & 0xFF; + int dataLenField = buffer[index + 3] & 0xFF; + int totalPacketLen = 4 + dataLenField; + + if (index + totalPacketLen > bufferLength) { + break; + } + + byte[] packetData = new byte[totalPacketLen]; + System.arraycopy(buffer, index, packetData, 0, totalPacketLen); + + if (verifyChecksum(packetData)) { + DataPacket packet = parseSinglePacket(packetData); + if (packet != null) { + packets.add(packet); + } + index += totalPacketLen; + } else { + index++; + } + } else { + index++; + } + } + + if (index > 0) { + int remaining = bufferLength - index; + System.arraycopy(buffer, index, buffer, 0, remaining); + bufferLength = remaining; + } + + return packets; + } + + private boolean verifyChecksum(byte[] packet) { + int len = packet.length; + if (len < 4) return false; + + int sum = 0; + for (int i = 2; i < len - 2; i++) { + sum += packet[i] & 0xFF; + } + sum = ~sum & 0xFFFF; + + int receivedChecksum = ((packet[len - 1] & 0xFF) << 8) | (packet[len - 2] & 0xFF); + + return sum == receivedChecksum; + } + + private DataPacket parseSinglePacket(byte[] packet) { + int sequence = packet[4] & 0xFF; + int tagId = ((packet[6] & 0xFF) << 8) | (packet[5] & 0xFF); + int baseId = ((packet[8] & 0xFF) << 8) | (packet[7] & 0xFF); + + int distance = (packet[12] << 24) | + ((packet[11] & 0xFF) << 16) | + ((packet[10] & 0xFF) << 8) | + (packet[9] & 0xFF); + + int battery = packet[13] & 0xFF; + int buttonStatus = packet[14] & 0xFF; + + return new DataPacket(sequence, + String.format("%04X", tagId), + String.format("%04X", baseId), + distance, battery, buttonStatus); + } + + public static class DataPacket { + private final int sequence; + private final String tagId; + private final String baseId; + private final int distance; + private final int battery; + private final int buttonStatus; + + public DataPacket(int sequence, String tagId, String baseId, + int distance, int battery, int buttonStatus) { + this.sequence = sequence; + this.tagId = tagId; + this.baseId = baseId; + this.distance = distance; + this.battery = battery; + this.buttonStatus = buttonStatus; + } + + @Override + public String toString() { + return String.format("包序: %d, 标签: %s, 基站: %s, 距离: %d mm, 电量: %d%%, 按键: %d", + sequence, tagId, baseId, distance, battery, buttonStatus); + } + } +} \ No newline at end of file diff --git a/src/window/ContentPanelFactory.java b/src/window/ContentPanelFactory.java index 7d39f09..6e9b00d 100644 --- a/src/window/ContentPanelFactory.java +++ b/src/window/ContentPanelFactory.java @@ -10,6 +10,7 @@ import dell_system.MapManagementPanel; import dell_system.MessageViewPanel; import dell_system.QuickCalculationPanel; +import dell_system.SerialCommPanel; import dell_system.SystemSettingsPanel; import dell_system.VersionInfoPanel; import dell_targets.BatteryRecordPanel; @@ -117,6 +118,8 @@ panel.add(new MapManagementPanel(messages), BorderLayout.CENTER); } else if (nodeName.equals(messages.getString("Quick_Calc"))) {// 蹇嵎璁$畻 panel.add(new QuickCalculationPanel(messages), BorderLayout.CENTER); + } else if (nodeName.equals(messages.getString("Serial_Port_Tool"))) {// 涓插彛宸ュ叿 + panel.add(new SerialCommPanel(messages), BorderLayout.CENTER); } else { // 瀵逛簬鏈疄鐜板姛鑳斤紝鏄剧ず寮�鍙戜腑鎻愮ず JLabel label = new JLabel(messages.getString("DEVELOPING") + ": " + nodeName, SwingConstants.CENTER); diff --git a/src/window/NavigationTreeFactory.java b/src/window/NavigationTreeFactory.java index 2bceb14..3e767c6 100644 --- a/src/window/NavigationTreeFactory.java +++ b/src/window/NavigationTreeFactory.java @@ -72,6 +72,7 @@ sysNode.add(new DefaultMutableTreeNode(messages.getString("DEPARTMENT_MANAGEMENT"))); // 部门管理 sysNode.add(new DefaultMutableTreeNode(messages.getString("MAP_MANAGEMENT")));//地图管理 sysNode.add(new DefaultMutableTreeNode(messages.getString("Quick_Calc"))); //快捷计算 + sysNode.add(new DefaultMutableTreeNode(messages.getString("Serial_Port_Tool"))); //串口工具 sysNode.add(new DefaultMutableTreeNode(messages.getString("VERSION_INFO"))); // 版本信息 root.add(sysNode); diff --git a/systemfile/20250724log.txt b/systemfile/20250724log.txt deleted file mode 100644 index d6b5732..0000000 --- a/systemfile/20250724log.txt +++ /dev/null @@ -1,2 +0,0 @@ -[2025-07-24 21:37:25] 数据更新失败: 执行SQL更新失败: Column 'map_type' cannot be null -SQL: INSERT INTO map (map_type, detail_display, offline_disappear, voice_enabled, fence_display, base_station_display, gateway_display, video_display, initial_view_position, view_height, map_heading_angle, map_tilt_angle, terrain_disabled, tile_map_loading, local_image_loading, basemap_disabled, three_d_model, located_layer, map_name, actual_x_length, actual_y_length, x0_coordinate, y0_coordinate, x_pixels, y_pixels, point_a_latlng_xy_coordinate, point_b_latlng_xy_coordinate, company, added_by, added_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) diff --git a/systemfile/20250726log.txt b/systemfile/20250726log.txt deleted file mode 100644 index 4f10472..0000000 --- a/systemfile/20250726log.txt +++ /dev/null @@ -1,2 +0,0 @@ -[2025-07-26 14:29:50] 数据更新失败: 执行SQL更新失败: Unknown column 'mapNameDetaile' in 'field list' -SQL: INSERT INTO map (map_type, detail_display, offline_disappear, voice_enabled, fence_display, base_station_display, gateway_display, video_display, initial_view_position, view_height, map_heading_angle, map_tilt_angle, terrain_disabled, tile_map_loading, local_image_loading, basemap_disabled, three_d_model, located_layer, map_name,mapNameDetaile, actual_x_length, actual_y_length, x0_coordinate, y0_coordinate, x_pixels, y_pixels, point_a_latlng_xy_coordinate, point_b_latlng_xy_coordinate, company, added_by, added_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) diff --git a/systemfile/20250805log.txt b/systemfile/20250805log.txt deleted file mode 100644 index 0e69da2..0000000 --- a/systemfile/20250805log.txt +++ /dev/null @@ -1,2 +0,0 @@ -[2025-08-05 22:51:21] 数据更新失败: 执行SQL更新失败: Parameter index out of range (41 > number of parameters, which is 40). -SQL: INSERT INTO fence (fence_type, fence_name, related_department, shape, valid_range_xy, valid_range_coordinates, effective_time, layer, expiration_time, color, is_enabled, bottom_height, top_height, gathering_radius, gathering_time, max_people, min_people, hazardous_material, max_duration, min_duration, latest_inspection_time, inspection_order, inspection_count, sides, can_enter, can_exit, constraint_type, constraint_description, camera_number, added_time, company, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6, reserved7, reserved8, reserved9, reserved10) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) diff --git a/systemfile/20250806log.txt b/systemfile/20250806log.txt deleted file mode 100644 index 3449736..0000000 --- a/systemfile/20250806log.txt +++ /dev/null @@ -1,10 +0,0 @@ -[2025-08-06 22:31:32] 数据更新失败: 执行SQL更新失败: Parameter index out of range (41 > number of parameters, which is 40). -SQL: INSERT INTO fence (fence_type, fence_name, related_department, shape, valid_range_xy, valid_range_coordinates, effective_time, layer, expiration_time, color, is_enabled, bottom_height, top_height, gathering_radius, gathering_time, max_people, min_people, hazardous_material, max_duration, min_duration, latest_inspection_time, inspection_order, inspection_count, sides, can_enter, can_exit, constraint_type, constraint_description, camera_number, added_time, company, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6, reserved7, reserved8, reserved9, reserved10) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) -[2025-08-06 22:32:00] 数据更新失败: 执行SQL更新失败: Parameter index out of range (41 > number of parameters, which is 40). -SQL: INSERT INTO fence (fence_type, fence_name, related_department, shape, valid_range_xy, valid_range_coordinates, effective_time, layer, expiration_time, color, is_enabled, bottom_height, top_height, gathering_radius, gathering_time, max_people, min_people, hazardous_material, max_duration, min_duration, latest_inspection_time, inspection_order, inspection_count, sides, can_enter, can_exit, constraint_type, constraint_description, camera_number, added_time, company, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6, reserved7, reserved8, reserved9, reserved10) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) -[2025-08-06 22:51:26] 数据更新失败: 执行SQL更新失败: Parameter index out of range (41 > number of parameters, which is 40). -SQL: INSERT INTO fence (fence_type, fence_name, related_department, shape, valid_range_xy, valid_range_coordinates, effective_time, layer, expiration_time, color, is_enabled, bottom_height, top_height, gathering_radius, gathering_time, max_people, min_people, hazardous_material, max_duration, min_duration, latest_inspection_time, inspection_order, inspection_count, sides, can_enter, can_exit, constraint_type, constraint_description, camera_number, added_time, company, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6, reserved7, reserved8, reserved9, reserved10) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) -[2025-08-06 23:10:10] 数据更新失败: 执行SQL更新失败: Parameter index out of range (41 > number of parameters, which is 40). -SQL: INSERT INTO fence (fence_type, fence_name, related_department, shape, valid_range_xy, valid_range_coordinates, effective_time, layer, expiration_time, color, is_enabled, bottom_height, top_height, gathering_radius, gathering_time, max_people, min_people, hazardous_material, max_duration, min_duration, latest_inspection_time, inspection_order, inspection_count, sides, can_enter, can_exit, constraint_type, constraint_description, camera_number, added_time, company, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6, reserved7, reserved8, reserved9, reserved10) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) -[2025-08-06 23:17:59] 数据更新失败: 执行SQL更新失败: Parameter index out of range (41 > number of parameters, which is 40). -SQL: INSERT INTO fence (fence_type, fence_name, related_department, shape, valid_range_xy, valid_range_coordinates, effective_time, layer, expiration_time, color, is_enabled, bottom_height, top_height, gathering_radius, gathering_time, max_people, min_people, hazardous_material, max_duration, min_duration, latest_inspection_time, inspection_order, inspection_count, sides, can_enter, can_exit, constraint_type, constraint_description, camera_number, added_time, company, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6, reserved7, reserved8, reserved9, reserved10) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) diff --git a/systemfile/20250807log.txt b/systemfile/20250807log.txt deleted file mode 100644 index 6d32e10..0000000 --- a/systemfile/20250807log.txt +++ /dev/null @@ -1,4 +0,0 @@ -[2025-08-07 08:15:08] 数据更新失败: 执行SQL更新失败: Parameter index out of range (41 > number of parameters, which is 40). -SQL: INSERT INTO fence (fence_type, fence_name, related_department, shape, valid_range_xy, valid_range_coordinates, effective_time, layer, expiration_time, color, is_enabled, bottom_height, top_height, gathering_radius, gathering_time, max_people, min_people, hazardous_material, max_duration, min_duration, latest_inspection_time, inspection_order, inspection_count, sides, can_enter, can_exit, constraint_type, constraint_description, camera_number, added_time, company, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6, reserved7, reserved8, reserved9, reserved10) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) -[2025-08-07 08:24:24] 数据更新失败: 执行SQL更新失败: Data truncation: Data too long for column 'point_b_latlng_xy_coordinate' at row 1 -SQL: UPDATE map SET map_type = ?, detail_display = ?, offline_disappear = ?, voice_enabled = ?, fence_display = ?, base_station_display = ?, gateway_display = ?, video_display = ?, initial_view_position = ?, view_height = ?, map_heading_angle = ?, map_tilt_angle = ?, terrain_disabled = ?, tile_map_loading = ?, local_image_loading = ?, basemap_disabled = ?, three_d_model = ?, located_layer = ?, map_name = ?, map_name_detaile = ?,actual_x_length = ?, actual_y_length = ?, x0_coordinate = ?, y0_coordinate = ?, x_pixels = ?, y_pixels = ?, point_a_latlng_xy_coordinate = ?, point_b_latlng_xy_coordinate = ?, company = ?, added_by = ?, added_time = ? WHERE id = ? diff --git a/systemfile/Messages_en.properties b/systemfile/Messages_en.properties index 4cf9cd7..1a9a709 100644 --- a/systemfile/Messages_en.properties +++ b/systemfile/Messages_en.properties @@ -1,3 +1,47 @@ +# New Resource Key-Value Pairs +packet.count.format=Packets Received: %d +label.id=Label ID +label.sequence=Packet Sequence +label.power=Battery Level +label.status=Status +label.tag_height=Tag Height +label.anchor_count=Anchor Count +label.anchor_ids=Anchor IDs +label.distances=Distance Values +label.anchor_powers=Anchor Battery Levels +status.button=Button +status.static=Static +status.sleeping=Sleeping +status.vibration=Vibration +status.uwb_switch=UWB Switch +parser.ready=Parser: Ready +yes=Yes +no=No +on=On +off=Off +HEX_SEND=Hex Send +Serial_Port_Tool=Serial Port Tool +SERIAL_PORT=Port +BAUD_RATE=Baud Rate +OPEN_SERIAL=Open Serial +CLOSE_SERIAL=Close Serial +HEX_DISPLAY=HEX Display +TIMESTAMP=Timestamp +APPEND_NEWLINE=Append Newline +TIMED_SEND=Timed Send +INTERVAL_MS=Interval (ms) +RAW_DATA_WINDOW=Raw Data Window +PARSED_DATA_WINDOW=Parsed Data Window +START=Start +PAUSE=Pause +RESUME=Resume +CLEAR=Clear +SEND_DATA=Send Data +SEND=Send +SELECT_PORT_ERROR=Please select a serial port +OPEN_PORT_ERROR=Error opening port +EMPTY_SEND_DATA=Send data is empty +INVALID_INTERVAL=Invalid interval value # New resource key\u2013value pairs map.dialog.selectMap=Select map.dialog.selectMapImage=Select Map Image diff --git a/systemfile/Messages_zh.properties b/systemfile/Messages_zh.properties index 2a2feda..b2607af 100644 --- a/systemfile/Messages_zh.properties +++ b/systemfile/Messages_zh.properties @@ -1,4 +1,62 @@ # 鏂板璧勬簮閿�煎 +packet.count.format=鏀跺埌鏁版嵁:%d鏉� +label.id=鏍囩缂栧彿 +label.sequence=鍖呭簭 +label.power=鐢甸噺 +label.status=鐘舵�� +label.tag_height=鏍囩楂� +label.anchor_count=鍩虹珯鏁� +label.anchor_ids=鍩虹珯缂栧彿 +label.distances=娴嬭窛鍊� +label.anchor_powers=鍩虹珯鐢甸噺 +status.button=鎸夐敭 +status.static=闈欐 +status.sleeping=浼戠湢 +status.vibration=闇囧姩 +status.uwb_switch=UWB寮�鍏� +parser.ready=瑙f瀽鍣�: 灏辩华 +yes=鏄� +no=鍚� +on=寮� +off=鍏� +ENABLE_PARSING=Enable Parsing +PARSER=Parser +EXPORT=Export +EXPORT_PARSED_DATA=Export Parsed Data +EXPORT_SUCCESS=Data exported successfully +EXPORT_FAILED=Export failed +INFO=Information +ENABLE_PARSING=鍚敤瑙f瀽 +PARSER=瑙f瀽鍣� +EXPORT=瀵煎嚭 +EXPORT_PARSED_DATA=瀵煎嚭宸茶В鏋愮殑鏁版嵁 +EXPORT_SUCCESS=鏁版嵁瀵煎嚭鎴愬姛 +EXPORT_FAILED=瀵煎嚭澶辫触 +INFO=淇℃伅 +HEX_SEND=Hex鍙戦�� +Serial_Port_Tool=涓插彛宸ュ叿 +SERIAL_PORT=涓插彛 +BAUD_RATE=閫夋嫨娉㈢壒鐜� +OPEN_SERIAL=鎵撳紑涓插彛 +CLOSE_SERIAL=鍏抽棴涓插彛 +HEX_DISPLAY=鍗佸叚杩涘埗鏄剧ず +TIMESTAMP=甯︽椂闂存埑鏄剧ず +APPEND_NEWLINE=闄勫姞鎹㈣绗� +TIMED_SEND=瀹氭椂鍙戦�� +INTERVAL_MS=闂撮殧锛堟绉掞級 +RAW_DATA_WINDOW=鍘熷鏁版嵁绐楀彛 +PARSED_DATA_WINDOW=瑙f瀽鏁版嵁绐楀彛 +START=寮�濮� +PAUSE=鏆傚仠 +RESUME=鎭㈠ +CLEAR=娓呯┖ +SEND_DATA=鍙戦�佹暟鎹� +SEND=鍙戦�� +SELECT_PORT_ERROR=璇烽�夋嫨涓插彛 +OPEN_PORT_ERROR=鎵撳紑涓插彛鍑洪敊 +EMPTY_SEND_DATA=鍙戦�佹暟鎹负绌� +INVALID_INTERVAL=鏃犳晥鐨勯棿闅斿�� +# 鏂板璧勬簮閿�煎 map.dialog.selectMap=閫夋嫨 map.dialog.selectMapImage=閫夋嫨鍦板浘鍥剧墖 map.dialog.imageFiles=鍥剧墖鏂囦欢 (*.jpg, *.png, *.jpeg) diff --git a/systemfile/logfile/openlog.txt b/systemfile/logfile/openlog.txt index 85329da..56da0b0 100644 --- a/systemfile/logfile/openlog.txt +++ b/systemfile/logfile/openlog.txt @@ -435,3 +435,123 @@ 程序关闭: 2025-08-07 09:27:57 工作时长: 0小时 0分钟 10秒 ----------------------------------- +程序启动: 2025-08-07 15:26:36 +程序关闭: 2025-08-07 15:49:00 +工作时长: 0小时 22分钟 24秒 +----------------------------------- +程序启动: 2025-08-07 15:49:02 +程序关闭: 2025-08-07 16:07:45 +工作时长: 0小时 18分钟 42秒 +----------------------------------- +程序启动: 2025-08-07 16:07:47 +程序关闭: 2025-08-07 16:22:13 +工作时长: 0小时 14分钟 26秒 +----------------------------------- +程序启动: 2025-08-07 16:22:15 +程序关闭: 2025-08-07 16:23:34 +工作时长: 0小时 1分钟 18秒 +----------------------------------- +程序启动: 2025-08-07 16:23:40 +程序关闭: 2025-08-07 16:31:55 +工作时长: 0小时 8分钟 15秒 +----------------------------------- +程序启动: 2025-08-07 16:31:58 +程序关闭: 2025-08-07 16:42:32 +工作时长: 0小时 10分钟 34秒 +----------------------------------- +程序启动: 2025-08-07 16:42:34 +程序关闭: 2025-08-07 16:54:32 +工作时长: 0小时 11分钟 58秒 +----------------------------------- +程序启动: 2025-08-07 16:54:35 +程序关闭: 2025-08-07 16:54:46 +工作时长: 0小时 0分钟 10秒 +----------------------------------- +程序启动: 2025-08-07 16:55:47 +程序关闭: 2025-08-07 17:03:48 +工作时长: 0小时 8分钟 1秒 +----------------------------------- +程序启动: 2025-08-07 17:03:50 +程序关闭: 2025-08-07 17:04:35 +工作时长: 0小时 0分钟 44秒 +----------------------------------- +程序启动: 2025-08-07 17:04:38 +程序关闭: 2025-08-07 17:06:23 +工作时长: 0小时 1分钟 45秒 +----------------------------------- +程序启动: 2025-08-07 17:06:26 +程序关闭: 2025-08-07 17:08:05 +工作时长: 0小时 1分钟 39秒 +----------------------------------- +程序启动: 2025-08-07 17:08:34 +程序关闭: 2025-08-07 17:09:07 +工作时长: 0小时 0分钟 32秒 +----------------------------------- +程序启动: 2025-08-07 17:13:45 +程序关闭: 2025-08-07 17:26:41 +工作时长: 0小时 12分钟 55秒 +----------------------------------- +程序启动: 2025-08-07 17:26:43 +程序关闭: 2025-08-07 17:49:13 +工作时长: 0小时 22分钟 29秒 +----------------------------------- +程序启动: 2025-08-07 17:49:41 +程序关闭: 2025-08-07 18:16:31 +工作时长: 0小时 26分钟 50秒 +----------------------------------- +程序启动: 2025-08-07 18:24:33 +程序关闭: 2025-08-07 18:28:24 +工作时长: 0小时 3分钟 50秒 +----------------------------------- +程序启动: 2025-08-07 18:40:06 +程序关闭: 2025-08-07 18:40:20 +工作时长: 0小时 0分钟 13秒 +----------------------------------- +程序启动: 2025-08-07 18:52:37 +程序关闭: 2025-08-07 18:54:05 +工作时长: 0小时 1分钟 28秒 +----------------------------------- +程序启动: 2025-08-07 18:54:06 +程序关闭: 2025-08-07 18:54:36 +工作时长: 0小时 0分钟 29秒 +----------------------------------- +程序启动: 2025-08-07 18:54:43 +程序关闭: 2025-08-07 18:55:44 +工作时长: 0小时 1分钟 0秒 +----------------------------------- +程序启动: 2025-08-07 19:08:21 +程序关闭: 2025-08-07 19:11:38 +工作时长: 0小时 3分钟 17秒 +----------------------------------- +程序启动: 2025-08-07 22:44:32 +程序关闭: 2025-08-07 23:07:41 +工作时长: 0小时 23分钟 9秒 +----------------------------------- +程序启动: 2025-08-07 23:07:43 +程序关闭: 2025-08-07 23:39:06 +工作时长: 0小时 31分钟 23秒 +----------------------------------- +程序启动: 2025-08-07 23:39:08 +程序关闭: 2025-08-07 23:39:49 +工作时长: 0小时 0分钟 41秒 +----------------------------------- +程序启动: 2025-08-07 23:42:02 +程序关闭: 2025-08-07 23:42:40 +工作时长: 0小时 0分钟 37秒 +----------------------------------- +程序启动: 2025-08-07 23:43:28 +程序关闭: 2025-08-07 23:44:31 +工作时长: 0小时 1分钟 3秒 +----------------------------------- +程序启动: 2025-08-07 23:44:33 +程序关闭: 2025-08-07 23:44:56 +工作时长: 0小时 0分钟 22秒 +----------------------------------- +程序启动: 2025-08-07 23:46:26 +程序关闭: 2025-08-07 23:52:05 +工作时长: 0小时 5分钟 39秒 +----------------------------------- +程序启动: 2025-08-07 23:52:07 +程序关闭: 2025-08-07 23:52:43 +工作时长: 0小时 0分钟 36秒 +----------------------------------- -- Gitblit v1.9.3