feat(HDMI-Tool): 光机串口下拉显示设备描述, CH344 多路口可辨

This commit is contained in:
2026-09-11 00:46:03 +08:00
parent 22d0969569
commit 1a9927d9bb
5 changed files with 60 additions and 16 deletions
+4 -2
View File
@@ -86,8 +86,10 @@ HDMI-Tool/
`protocols.md` 为准:命令帧 `D5 01 LEN <ASCII命令> CRC`、响应帧 `B5 TYPE LEN <payload> CRC`
CRC 为第 2 字节起累加和取低 8 位。
GUI"光机控制"区:选串口 → 连接 → 点快捷按钮或命令下拉/自定义输入发送;日志区实时显示
`→ 命令` / `← 译码结果 (原始 hex)`,错误自动附释义(如 `err:3I2C NACK`)。
GUI"光机控制"区:选串口 → 连接 → 点快捷按钮或命令下拉/自定义输入发送;串口下拉显示
"COMx + 设备描述"CH344 等多路适配器每一路描述不同(如 serial-A/B/C/D),据此选口;
多口描述相同时自动附物理位置消歧。日志区实时显示 `→ 命令` / `← 译码结果 (原始 hex)`
错误自动附释义(如 `err:3I2C NACK`)。
| 命令 | 功能 | 响应示例 |
|---|---|---|
Binary file not shown.
+1
View File
@@ -192,6 +192,7 @@ HDMI-Tool/
├── release/ # 构建与发布产物(机器生成区, 不手改)
│ ├── HDMI-Tool.exe # 打包单文件版(改动跟随源码提交入库)
│ ├── pattern_slots.json # exe 运行配置(栏位预置 + 串口记忆)
│ ├── *.png / README.md # 附属文件平铺副本(由 package_release.py 从 assets/ 同步)
│ └── *.zip # 发布包(不入库, 上传 Gitea Release
├── README.md # 本说明
└── AGENTS.md # 面向 AI/Agent 的工程档案(结构/约定/构建规程)
+23 -3
View File
@@ -168,11 +168,31 @@ class DLPC485:
threading.Thread(target=self._run, daemon=True).start()
@staticmethod
def list_ports():
"""枚举本机串口名(未装 pyserial 返回空表)"""
def list_ports_info():
"""枚举串口, 返回 [(设备名, 显示标签), ...]。
标签 = "COMx 设备描述"(描述里的 "(COMx)" 尾巴去掉, COM 号已在最前),
CH344 这类多路适配器的每一路描述不同(如 serial-A/B/C/D), 依此区分;
多口描述完全相同(同型号多口)时追加物理位置/序列号消歧。
"""
if not HAS_SERIAL:
return []
return [p.device for p in serial.tools.list_ports.comports()]
items = []
for p in serial.tools.list_ports.comports():
desc = re.sub(r'\s*\((COM\d+)\)\s*$', '', (p.description or '').strip(),
flags=re.I)
if desc.upper() == p.device.upper():
desc = ''
label = f'{p.device} {desc}'.rstrip()
tail = p.location or p.serial_number or ''
items.append((p.device, label, tail))
counts = collections.Counter(label for _d, label, _t in items)
out = []
for dev, label, tail in items:
if counts[label] > 1 and tail: # 同标签多口: 附物理位置消歧
label = f'{label} [{tail}]'
out.append((dev, label))
return out
def open(self, port, baud=DEFAULT_BAUD):
if not HAS_SERIAL:
+32 -11
View File
@@ -1179,10 +1179,12 @@ def run_gui(auto_close=0):
r1 = ttk.Frame(grp2)
r1.pack(fill='x')
ttk.Label(r1, text='串口:').pack(side='left')
self.cbo_dlpc = ttk.Combobox(r1, width=12, state='readonly',
values=dlpc_rs485.DLPC485.list_ports())
# 下拉显示 "COMx + 设备描述"(CH344 四路按 serial-A/B/C/D 等描述区分)
self._dlpc_ports = dlpc_rs485.DLPC485.list_ports_info()
self.cbo_dlpc = ttk.Combobox(r1, width=22, state='readonly',
values=[lb for _d, lb in self._dlpc_ports])
if SERIAL_CFG['port']:
self.cbo_dlpc.set(SERIAL_CFG['port'])
self._dlpc_pick(SERIAL_CFG['port'])
self.cbo_dlpc.pack(side='left', padx=(4, 2))
ttk.Button(r1, text='刷新', width=6,
command=self._dlpc_refresh).pack(side='left')
@@ -1341,7 +1343,7 @@ def run_gui(auto_close=0):
if connected != self._dlpc_connected:
self._dlpc_connected = connected
self.btn_dlpc.config(text='断开' if connected else '连接')
self.after(80, self._poll_dlpc)
self._dlpc_after_id = self.after(80, self._poll_dlpc)
def _dlpc_log(self, line):
self.txt_dlpc.configure(state='normal')
@@ -1352,18 +1354,33 @@ def run_gui(auto_close=0):
self.txt_dlpc.configure(state='disabled')
def _dlpc_refresh(self):
ports = dlpc_rs485.DLPC485.list_ports()
self.cbo_dlpc['values'] = ports
if SERIAL_CFG['port'] in ports:
self.cbo_dlpc.set(SERIAL_CFG['port'])
elif ports:
self.cbo_dlpc.current(0)
self._dlpc_ports = dlpc_rs485.DLPC485.list_ports_info()
self.cbo_dlpc['values'] = [lb for _d, lb in self._dlpc_ports]
devices = [d for d, _l in self._dlpc_ports]
if SERIAL_CFG['port'] in devices:
self._dlpc_pick(SERIAL_CFG['port'])
elif devices:
self._dlpc_pick(devices[0])
def _dlpc_pick(self, device):
"""按 COM 口名选中下拉项(下拉显示的是带描述的标签)"""
for i, (d, _label) in enumerate(self._dlpc_ports):
if d == device:
self.cbo_dlpc.current(i)
return
def _dlpc_selected_port(self):
"""当前下拉选中的 COM 口名"""
i = self.cbo_dlpc.current()
if 0 <= i < len(self._dlpc_ports):
return self._dlpc_ports[i][0]
return self.cbo_dlpc.get().strip()
def _dlpc_toggle(self):
if self.dlpc.is_connected():
self.dlpc.close()
return
port = self.cbo_dlpc.get().strip()
port = self._dlpc_selected_port()
if not port:
self.lbl_dlpc_st.config(text='未选择串口', foreground='#B05000')
return
@@ -1405,6 +1422,10 @@ def run_gui(auto_close=0):
self._dlpc_send(f'M731S{v}')
def destroy(self):
try: # 取消待触发的轮询回调, 避免销毁后 Tcl 报错
self.after_cancel(self._dlpc_after_id)
except (KeyError, AttributeError, Exception):
pass
try: # 两种退出路径(关窗/--seconds 自动关)都收掉串口线程
self.dlpc.close()
except Exception: