feat(HDMI-Tool): 光机串口下拉显示设备描述, CH344 多路口可辨
This commit is contained in:
+4
-2
@@ -86,8 +86,10 @@ HDMI-Tool/
|
||||
`protocols.md` 为准:命令帧 `D5 01 LEN <ASCII命令> CRC`、响应帧 `B5 TYPE LEN <payload> CRC`,
|
||||
CRC 为第 2 字节起累加和取低 8 位。
|
||||
|
||||
GUI"光机控制"区:选串口 → 连接 → 点快捷按钮或命令下拉/自定义输入发送;日志区实时显示
|
||||
`→ 命令` / `← 译码结果 (原始 hex)`,错误自动附释义(如 `err:3(I2C NACK)`)。
|
||||
GUI"光机控制"区:选串口 → 连接 → 点快捷按钮或命令下拉/自定义输入发送;串口下拉显示
|
||||
"COMx + 设备描述",CH344 等多路适配器每一路描述不同(如 serial-A/B/C/D),据此选口;
|
||||
多口描述相同时自动附物理位置消歧。日志区实时显示 `→ 命令` / `← 译码结果 (原始 hex)`,
|
||||
错误自动附释义(如 `err:3(I2C NACK)`)。
|
||||
|
||||
| 命令 | 功能 | 响应示例 |
|
||||
|---|---|---|
|
||||
|
||||
Binary file not shown.
@@ -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 的工程档案(结构/约定/构建规程)
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user