Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fde79c071 | ||
|
|
b4328b8be6 | ||
|
|
4149d203b0 | ||
|
|
264a0c74a6 | ||
|
|
190cf29aa5 | ||
|
|
d658fd459a | ||
|
|
b627f79dad |
+58
-8
@@ -6,9 +6,9 @@
|
||||
|
||||
## 1. 项目定位
|
||||
|
||||
仓库 `LT8619C_Debug_Tools` 是 LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板的**调试上位机工具集**,
|
||||
仓库 `HW-Debug-Tools` 是 LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板的**调试上位机工具集**,
|
||||
上游主仓库(固件)为 `hulk/LT8619C_DLPC3421_HDMI`(同 Gitea 实例 `gitea.hulk.wang`),
|
||||
上游固件本机路径 `E:\Hulk-Coding\LT8619C_DLPC3421_HDMI`;工具仓库路径 `E:\Hulk-Coding\LT8619C_Debug_Tools`。
|
||||
上游固件本机路径 `E:\Hulk-Coding\LT8619C_DLPC3421_HDMI`;工具仓库路径 `E:\Hulk-Coding\HW-Debug-Tools`。
|
||||
DLPilot 工作在两端:HDMI **源端**(PC 显卡侧,EDID/分辨率/图案)与**光机控制端**
|
||||
(RS485 → 板载 GD32E230 网关 → DLPC3421)。寄存器语义判读基线(0x606E 位交换 /
|
||||
0x606D 整组顺序)与光机协议规程都在上游仓库 `doc/architecture/` 与 `protocols.md`,不在本仓库。
|
||||
@@ -92,6 +92,13 @@ DLPilot/
|
||||
五卡(显示器/模式/EDID 信息/测试图案/hex),右列光机五卡(串口/数据/电源/命令/滑条),
|
||||
支持的模式和 EDID 信息默认折叠;顶栏 Dark/Light/System 切换。Light/Dark 同时更新
|
||||
Fluent 主题、Qt 调色板、容器样式与 Windows DWM 标题栏,勿只调用 setTheme。
|
||||
**fluent 控件的自定义样式禁止直接 setStyleSheet**:setTheme 会用库自带 qss 重刷全部
|
||||
已注册控件,直写样式随之丢失(v0.4.0 swatch 丢底色的根因)。须走
|
||||
`setCustomStyleSheet(控件, lightQss, darkQss)`(qss 需覆盖 hover/pressed/disabled 态,
|
||||
否则悬停瞬间被自带态样式盖回);仅 PushButton 等无 themeChanged 钩子的控件可幸存。
|
||||
FluentLabelBase 系(StrongBodyLabel 等)例外:其 setTextColor 在每次切主题时整体重写
|
||||
自定义槽,任何 setCustomStyleSheet 都会被冲掉——字号等改用 QFont(自带 label.qss 无
|
||||
font-size 规则,QFont 不会被冲)。RGB swatch 底色回归测试见 selftest_theme.py。
|
||||
PD 协议成功显示绿色,FPDO 仍独立判定。打包必须收集 `qfluentwidgets` 资源,并加入 Windows 系统 `icuuc.dll`,否则 QtCore 可能被其它 ICU DLL 解析失败。
|
||||
|
||||
## 4. 领域语义(测试值都有含义,勿"顺手改")
|
||||
@@ -155,6 +162,9 @@ python publish_gitea.py ../release/DLPilot-v<版本>-win64.zip --replace --insec
|
||||
- GUI 与 hdmi_source.ps1 各自独立实现显示器枚举,行为可能微差(GUI 与 `-List` 序号一致,
|
||||
但与"设置"面板序号无保证);多屏操作前先确认序号;
|
||||
- `pattern_slots.json` 兼容两种历史格式,写出只写新格式(详见 §3.11);
|
||||
- `--seconds` 冒烟在已有 DLPilot 实例(含用户开着的 exe)运行时会"挂起":run_gui
|
||||
检测到单实例互斥后弹模态框等点击。无头验证改用直启 `App(5)` 的等效脚本,或先关实例;
|
||||
重打包同理——build_exe.py 会 taskkill 同名进程,等于替用户关掉开着的实例;
|
||||
- 旧版 `app_gui.py` 仅保留作历史对照,当前入口使用 `app_fluent.py`;新增或修改界面时
|
||||
应遵循 PySide6-Fluent-Widgets 的控件和 Qt 布局,不要把旧版 CustomTkinter 依赖带回入口。
|
||||
|
||||
@@ -162,12 +172,14 @@ python publish_gitea.py ../release/DLPilot-v<版本>-win64.zip --replace --insec
|
||||
|
||||
1. `python -m compileall -q src`(在 DLPilot/ 下) —— 全模块可编译;
|
||||
2. `python selftest_rs485.py` —— 光机协议回归(改 dlpc_rs485.py 后必跑,向量来自上游 protocols.md);
|
||||
3. `python hdmi_gui.py --seconds 5` —— GUI 冒烟(自动开关);
|
||||
4. `python hdmi_gui.py --test-pattern Checker --area 800x600 --seconds 3` —— 投图链路;
|
||||
5. `python hdmi_gui.py --dump` —— EDID 解算不抛异常;
|
||||
6. `python hdmi_gui.py --dlpc-cmd M999`(不带 --port)—— 应明确报错而非崩溃(无硬件时的优雅降级);
|
||||
7. `python build_exe.py` → 双击 release/DLPilot.exe 确认图标/双栏布局/投图/光机区渲染;
|
||||
8. `python package_release.py <版本>` —— 不报"引用图片缺失"即栏位完整性 OK。
|
||||
3. `python selftest_theme.py` —— 主题切换回归(改 app_fluent.py 涉及样式/主题后必跑;
|
||||
离屏渲染,Dark/Light 往返后校验 swatch 底色样式与渲染像素、标题字号);
|
||||
4. `python hdmi_gui.py --seconds 5` —— GUI 冒烟(自动开关);
|
||||
5. `python hdmi_gui.py --test-pattern Checker --area 800x600 --seconds 3` —— 投图链路;
|
||||
6. `python hdmi_gui.py --dump` —— EDID 解算不抛异常;
|
||||
7. `python hdmi_gui.py --dlpc-cmd M999`(不带 --port)—— 应明确报错而非崩溃(无硬件时的优雅降级);
|
||||
8. `python build_exe.py` → 双击 release/DLPilot.exe 确认图标/双栏布局/投图/光机区渲染;
|
||||
9. `python package_release.py <版本>` —— 不报"引用图片缺失"即栏位完整性 OK。
|
||||
|
||||
## 8. v0.4.0 进度记录(2026-09-24)
|
||||
|
||||
@@ -180,3 +192,41 @@ python publish_gitea.py ../release/DLPilot-v<版本>-win64.zip --replace --insec
|
||||
发布使用仓库预置配置,临时打包后恢复本机文件。
|
||||
- 关联动态:EDID-Viewer 已于 2026-09-25 从本工具的"源端 EDID 查看"需求独立成工具
|
||||
入库并发布 v0.1.0,与本目录无代码共享;I2C-Inject 已标记暂停开发(详见根 `agent.md`)。
|
||||
|
||||
## 9. v0.4.0 后修复记录
|
||||
|
||||
- 2026-09-28 修复"切换 Light 后 R/G/B hex 按钮底色丢失、切回 Dark 也不恢复":根因是
|
||||
fluent 控件直接 `setStyleSheet` 的自定义样式在 `setTheme` 时被库重刷的自带 qss 整体
|
||||
覆盖(任何方向的切换都会丢,非 Light 特有)。swatch 改走 `setCustomStyleSheet`(qss
|
||||
覆盖 hover/pressed/disabled 态),同病的顶栏标题 24px 字号改用 QFont(FluentLabelBase
|
||||
的自定义槽被库的 setTextColor 每次切主题重写,见 §3.12)。新增 `src/selftest_theme.py`
|
||||
离屏回归(样式表存活 + 渲染像素比对),本次验证:compileall / selftest_rs485 /
|
||||
selftest_theme / GUI 冒烟全部通过。
|
||||
- 2026-09-28 以 v0.4.1 重新打包:APP_VERSION → 0.4.1,`build_exe.py` 生成新
|
||||
release/DLPilot.exe(67.1 MB,exe `--seconds 5` 定时退出冒烟 exit 0),按 §8 约定
|
||||
临时还原预置 pattern_slots.json 后 `package_release.py 0.4.1` 生成
|
||||
`DLPilot-v0.4.1-win64.zip`(66.8 MB,zip 内为预置 COM15 配置,本机 COM5 运行态
|
||||
已还原未入库)。Gitea Release 已发布:tag `DLPilot-v0.4.1` 指向提交 `62b325c`
|
||||
(源码+exe+文档同一提交),资产 `DLPilot-v0.4.1-win64.zip`(66.8 MB),
|
||||
https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases/tag/DLPilot-v0.4.1 。
|
||||
发布说明用 --notes-file 传入(内置 DEFAULT_NOTES 模板还是 v0.1.0 旧内容,下次
|
||||
发布记得先写说明文件)。
|
||||
- 2026-09-28 第二修:"串口未选/选错点连接后窗口被拉长、刷新按钮够不到"。根因:
|
||||
pyserial 原始异常串(`could not open port '': FileNotFoundError...`)整段塞进
|
||||
状态 BodyLabel,QLabel 不换行时最小宽度=整行文本宽,把右列参数行最小宽度撑爆。
|
||||
三层修复:①`_dlpc_toggle` 空串口直接短提示返回(不再先写 SERIAL_CFG/save_slots
|
||||
再 open——旧代码这顺序还会把本机串口记忆覆写成空串,本机 COM5 记忆即这样丢失过,
|
||||
已手工修回);②dlpc_rs485 open 失败消息分类为短提示(被占用/不存在/其它),
|
||||
完整异常改走 on_event 进收发日志;③`lbl_dlpc_st.setWordWrap(True)` 兜底。
|
||||
验证:compileall / selftest_rs485 ALL PASS / 离屏断言(空串口提示、长文本下标签
|
||||
最小宽度<300 可换行)/ GUI 冒烟 / 新 exe `--seconds 5` exit 0;v0.4.1 exe(15:05)
|
||||
与 zip 均已用该修复重打。
|
||||
- 2026-09-28 v0.4.2 两处 UI 小修:①"串口数据 · 收发日志"卡的"清空"按钮原本自占
|
||||
一行(_card 的标题行是独立 row,按钮行加在其下),与标题错位且多占一行高度——
|
||||
`_card()` 增加 `trailing` 参数把按钮并入标题行右端;②v0.4.0 fluent 重写把旧版
|
||||
app_gui.py 光机命令卡首行的快捷按钮排(开光机/关光机/查版本/软件重启/开TEC/
|
||||
关TEC/TEC33.0°C)整行丢失,开/关光机只能走预设下拉——本次按旧版排布原样恢复,
|
||||
位于电流行与预设行之间(命令直发 `_dlpc_send`,无新增协议逻辑)。
|
||||
验证:compileall / selftest_rs485 / selftest_theme ALL PASS;离屏渲染断言"清空"
|
||||
与标题垂直中心差 0px、7 个快捷按钮齐全;真实桌面冒烟 exit 0。APP_VERSION → 0.4.2
|
||||
并重打包。
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
> HDMI **源端**(EDID 查看、分辨率切换、纯色/测试图案投屏)+ **光机控制**
|
||||
> (RS485 直连板上 GD32 网关,开关光机/设光强/查温度电流)。
|
||||
>
|
||||
> - **只想用工具**:到 [Gitea Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases)
|
||||
> - **只想用工具**:到 [Gitea Releases](https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases)
|
||||
> 下载 `DLPilot-vX.Y.Z-win64.zip`,解压双击 `DLPilot.exe` 即可(Windows 10/11 x64,免安装、无需 Python)。
|
||||
> - **要改代码/重新打包**:见 §8、§9。
|
||||
>
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
## 2. 下载与安装
|
||||
|
||||
1. 打开 [Releases 页面](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases),取最新的
|
||||
1. 打开 [Releases 页面](https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases),取最新的
|
||||
`DLPilot-vX.Y.Z-win64.zip`;
|
||||
2. 解压到**任意可写目录**(自定义图片与栏位配置会写到 exe 旁边);
|
||||
3. 双击 `DLPilot.exe`。首次启动比脚本慢一两秒(onefile 解压),属正常现象。
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
> HDMI **源端**(EDID 查看、分辨率切换、纯色/测试图案投屏)+ **光机控制**
|
||||
> (RS485 直连板上 GD32 网关,开关光机/设光强/查温度电流)。
|
||||
>
|
||||
> - **只想用工具**:到 [Gitea Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases)
|
||||
> - **只想用工具**:到 [Gitea Releases](https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases)
|
||||
> 下载 `DLPilot-vX.Y.Z-win64.zip`,解压双击 `DLPilot.exe` 即可(Windows 10/11 x64,免安装、无需 Python)。
|
||||
> - **要改代码/重新打包**:见 §8、§9。
|
||||
>
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
## 2. 下载与安装
|
||||
|
||||
1. 打开 [Releases 页面](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases),取最新的
|
||||
1. 打开 [Releases 页面](https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases),取最新的
|
||||
`DLPilot-vX.Y.Z-win64.zip`;
|
||||
2. 解压到**任意可写目录**(自定义图片与栏位配置会写到 exe 旁边);
|
||||
3. 双击 `DLPilot.exe`。首次启动比脚本慢一两秒(onefile 解压),属正常现象。
|
||||
|
||||
+34
-11
@@ -52,7 +52,8 @@ from PySide6.QtWidgets import (
|
||||
)
|
||||
from qfluentwidgets import (
|
||||
BodyLabel, CardWidget, ComboBox, LineEdit, PlainTextEdit,
|
||||
PrimaryPushButton, PushButton, Slider, StrongBodyLabel, Theme, setTheme,
|
||||
PrimaryPushButton, PushButton, Slider, StrongBodyLabel, Theme,
|
||||
setCustomStyleSheet, setTheme,
|
||||
)
|
||||
|
||||
import config
|
||||
@@ -62,8 +63,8 @@ import edid_parse
|
||||
import patterns
|
||||
|
||||
APP_NAME = "DLPilot"
|
||||
APP_VERSION = "0.4.0"
|
||||
REPO_URL = "https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools"
|
||||
APP_VERSION = "0.4.2"
|
||||
REPO_URL = "https://gitea.hulk.wang/hulk/HW-Debug-Tools"
|
||||
MONO = QFont("Consolas", 10)
|
||||
CHIP_IDLE = "#666666"
|
||||
CHIP_OK = "#2FA574"
|
||||
@@ -209,7 +210,7 @@ class App(QMainWindow):
|
||||
button.clicked.connect(callback)
|
||||
return button
|
||||
|
||||
def _card(self, title, parent):
|
||||
def _card(self, title, parent, trailing=None):
|
||||
card = CardWidget(parent)
|
||||
layout = QVBoxLayout(card)
|
||||
layout.setContentsMargins(14, 12, 14, 14)
|
||||
@@ -217,6 +218,8 @@ class App(QMainWindow):
|
||||
row = QHBoxLayout()
|
||||
row.addWidget(StrongBodyLabel(title, card))
|
||||
row.addStretch(1)
|
||||
if trailing is not None:
|
||||
row.addWidget(trailing)
|
||||
layout.addLayout(row)
|
||||
return card, layout
|
||||
|
||||
@@ -266,7 +269,12 @@ class App(QMainWindow):
|
||||
outer.setSpacing(12)
|
||||
header = QHBoxLayout()
|
||||
title = StrongBodyLabel("DLPilot", root)
|
||||
title.setStyleSheet("font-size: 24px; font-weight: 700;")
|
||||
# 标题字号走 QFont:FluentLabelBase 在每次主题切换时会用自带的颜色规则
|
||||
# 重写自定义 qss 槽,setStyleSheet/setCustomStyleSheet 写的字号都会被冲掉
|
||||
title_font = title.font()
|
||||
title_font.setPixelSize(24)
|
||||
title_font.setBold(True)
|
||||
title.setFont(title_font)
|
||||
header.addWidget(title)
|
||||
header.addWidget(BodyLabel("EDID · 测试图案 · RS485 光机控制", root))
|
||||
header.addStretch(1)
|
||||
@@ -355,7 +363,13 @@ class App(QMainWindow):
|
||||
row.addWidget(BodyLabel(f"{channel}: 0x", card))
|
||||
for label, color in items:
|
||||
button = PushButton(label, card)
|
||||
button.setStyleSheet(f"PushButton {{ background: {color}; color: {'black' if color == '#00FF00' else 'white'}; }}")
|
||||
# fluent 控件的样式须走 setCustomStyleSheet:直接 setStyleSheet 的内容
|
||||
# 会在 setTheme 时被库重刷的自带 qss 冲掉;且须覆盖 hover/pressed 态,
|
||||
# 否则悬停瞬间底色仍会被自带态样式盖回
|
||||
fg = 'black' if color == '#00FF00' else 'white'
|
||||
qss = ("PushButton, PushButton:hover, PushButton:pressed, "
|
||||
f"PushButton:disabled {{ background-color: {color}; color: {fg}; border: none; }}")
|
||||
setCustomStyleSheet(button, qss, qss)
|
||||
button.clicked.connect(lambda checked=False, c=color: self._show_solid(c))
|
||||
row.addWidget(button)
|
||||
row.addStretch(1)
|
||||
@@ -414,16 +428,16 @@ class App(QMainWindow):
|
||||
setattr(self, attr, combo)
|
||||
params.addWidget(combo)
|
||||
self.lbl_dlpc_st = BodyLabel("未连接", card)
|
||||
# 状态标签允许换行兜底: 任何长错误串都不得撑大参数行最小宽度(否则窗口拉长,
|
||||
# 刷新/连接按钮被挤出可视区)
|
||||
self.lbl_dlpc_st.setWordWrap(True)
|
||||
params.addWidget(self.lbl_dlpc_st)
|
||||
params.addStretch(1)
|
||||
body.addLayout(params)
|
||||
layout.addWidget(card)
|
||||
|
||||
card, body = self._card("串口数据 · 收发日志(译码 + 原始 hex)", self)
|
||||
row = QHBoxLayout()
|
||||
row.addStretch(1)
|
||||
row.addWidget(self._button("清空", self._dlpc_clear))
|
||||
body.addLayout(row)
|
||||
card, body = self._card("串口数据 · 收发日志(译码 + 原始 hex)", self,
|
||||
trailing=self._button("清空", self._dlpc_clear))
|
||||
self.txt_dlpc = self._text()
|
||||
self.txt_dlpc.setMinimumHeight(230)
|
||||
body.addWidget(self.txt_dlpc)
|
||||
@@ -457,6 +471,14 @@ class App(QMainWindow):
|
||||
row.addStretch(1)
|
||||
row.addWidget(self._button("查电流", self._query_current))
|
||||
body.addLayout(row)
|
||||
# 快捷命令行: v0.4.0 重写时从旧版 app_gui.py 丢失, 开关光机等一发命令
|
||||
# 不应只能走预设下拉
|
||||
quick = QHBoxLayout()
|
||||
for name, cmd in (("开光机", "M730S0"), ("关光机", "M730S1"), ("查版本", "M999"),
|
||||
("软件重启", "M888"), ("开TEC", "M7S0"), ("关TEC", "M7S1"),
|
||||
("TEC33.0°C", "M8S330")):
|
||||
quick.addWidget(self._button(name, lambda checked=False, c=cmd: self._dlpc_send(c)))
|
||||
body.addLayout(quick)
|
||||
preset_row = QHBoxLayout()
|
||||
self._dlpc_presets = [(n, cmd) for n, cmd, _ in dlpc_rs485.PRESETS]
|
||||
self.cbo_dlpc_cmd = ComboBox(card)
|
||||
@@ -770,6 +792,7 @@ class App(QMainWindow):
|
||||
def _dlpc_toggle(self):
|
||||
if self.dlpc.is_connected(): self.dlpc.close(); self._serial_reset_state(); return
|
||||
port = self._dlpc_selected_port()
|
||||
if not port: self.lbl_dlpc_st.setText('未选择串口,请先选择或刷新'); return
|
||||
try: baud, bytesize, stopbits = int(self.cbo_baud.currentText()), int(self.cbo_databits.currentText()), int(self.cbo_stopbits.currentText())
|
||||
except ValueError: self.lbl_dlpc_st.setText("串口参数非法"); return
|
||||
parity = self.cbo_parity.currentText()[:1] or 'N'; config.SERIAL_CFG.update(port=port, baud=baud, bytesize=bytesize, parity=parity, stopbits=stopbits); config.save_slots(self.slots, self.cbo_area.currentText()); self.dlpc.open(port, baud, bytesize=bytesize, parity=parity, stopbits=stopbits)
|
||||
|
||||
@@ -41,7 +41,7 @@ CHIP_ERR = '#D9534F'
|
||||
|
||||
APP_NAME = 'DLPilot'
|
||||
APP_VERSION = '0.3.6'
|
||||
REPO_URL = 'https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools'
|
||||
REPO_URL = 'https://gitea.hulk.wang/hulk/HW-Debug-Tools'
|
||||
|
||||
|
||||
def get_icon_path():
|
||||
|
||||
@@ -326,11 +326,19 @@ class DLPC485:
|
||||
self.ser = None
|
||||
with self._lock:
|
||||
self._target = None
|
||||
et = str(e)
|
||||
if 'PermissionError' in repr(e) or '拒绝访问' in et \
|
||||
or 'Access is denied' in et:
|
||||
et += '(串口被占用: 检查串口助手/另一个本工具实例)'
|
||||
self.on_status(f'连接失败: {et}')
|
||||
blob = str(e) + repr(e)
|
||||
if 'PermissionError' in blob or '拒绝访问' in blob \
|
||||
or 'Access is denied' in blob:
|
||||
hint = '串口被占用(串口助手/另一实例?)'
|
||||
elif 'FileNotFoundError' in blob or '找不到指定的' in blob \
|
||||
or 'No such file' in blob:
|
||||
hint = '串口不存在,请刷新后重选'
|
||||
else:
|
||||
hint = '无法打开,详情见日志'
|
||||
# 状态标签只放短提示(长异常串会撑爆参数行把窗口拉长),
|
||||
# 完整异常走 on_event 进收发日志
|
||||
self.on_status(f'连接失败: {hint}')
|
||||
self.on_event(f'连接失败: {e!r}')
|
||||
if self.ser is not None:
|
||||
try:
|
||||
item = None
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# coding: utf-8
|
||||
"""主题切换回归自检(无窗口, 离屏渲染)。
|
||||
|
||||
背景: fluent 控件直接 setStyleSheet 的样式会在 setTheme 时被库重刷的自带 qss 冲掉
|
||||
(v0.4.0 RGB swatch 按钮切主题丢底色的根因)。swatch 改走 setCustomStyleSheet、
|
||||
标题字号走 QFont 后,本测试保证:
|
||||
1. Dark -> Light -> Dark -> Light 往返后 9 个 swatch 按钮样式表仍带底色;
|
||||
2. Light 下实际渲染出的按钮中心像素 = swatch 色值(不只样式表字符串存在);
|
||||
3. 标题 24px 加粗(QFont)在往返后不变。
|
||||
|
||||
运行: python selftest_theme.py (依赖 PySide6-Fluent-Widgets)
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from PySide6.QtGui import QColor
|
||||
from PySide6.QtWidgets import QApplication
|
||||
from qfluentwidgets import PushButton, StrongBodyLabel, Theme, setTheme
|
||||
|
||||
import app_fluent
|
||||
import patterns
|
||||
|
||||
|
||||
def check_style_sheet(win, app):
|
||||
swatches = [b for b in win.findChildren(PushButton) if b.text() in {"55", "AA", "FF"}]
|
||||
assert len(swatches) == 9, f"expect 9 swatch buttons, got {len(swatches)}"
|
||||
title = [l for l in win.findChildren(StrongBodyLabel) if l.text() == "DLPilot"]
|
||||
assert len(title) == 1, "title label not found"
|
||||
colored = sum(1 for b in swatches if "background-color: #" in b.styleSheet())
|
||||
f = title[0].font()
|
||||
print(f" swatch 样式表带底色: {colored}/9, 标题 24px 粗体: "
|
||||
f"{f.pixelSize() == 24 and f.bold()}")
|
||||
return colored == 9 and f.pixelSize() == 24 and f.bold()
|
||||
|
||||
|
||||
def check_rendered_pixel(win, app):
|
||||
"""Light 主题下逐个渲染 swatch,与目标色一致的像素须占明显多数(背景为主,
|
||||
中心处是文字字形,不能只采单点)。"""
|
||||
ok = True
|
||||
for channel, items in patterns.SOLID_ROWS:
|
||||
for label, color in items:
|
||||
button = next(b for b in win.findChildren(PushButton)
|
||||
if b.text() == label and f"background-color: {color}" in b.styleSheet())
|
||||
image = button.grab().toImage()
|
||||
target = QColor(color)
|
||||
total, matched = image.width() * image.height(), 0
|
||||
for y in range(image.height()):
|
||||
for x in range(image.width()):
|
||||
if image.pixelColor(x, y) == target:
|
||||
matched += 1
|
||||
ratio = matched / total
|
||||
same = ratio >= 0.2
|
||||
ok &= same
|
||||
if not same:
|
||||
print(f" 渲染不符: {channel}/{label} 期望 {color} 仅占 {ratio:.0%}")
|
||||
print(f" Light 下渲染像素比对: {'一致' if ok else '存在偏差'}")
|
||||
return ok
|
||||
|
||||
|
||||
def main():
|
||||
app = QApplication.instance() or QApplication(sys.argv)
|
||||
setTheme(Theme.AUTO)
|
||||
win = app_fluent.App(0)
|
||||
passed = True
|
||||
for step, theme in (("初始 Dark", Theme.DARK), ("切 Light", Theme.LIGHT),
|
||||
("切回 Dark", Theme.DARK), ("再切 Light", Theme.LIGHT)):
|
||||
setTheme(theme)
|
||||
app.processEvents()
|
||||
print(f"[{step}]")
|
||||
passed &= check_style_sheet(win, app)
|
||||
if theme == Theme.LIGHT:
|
||||
passed &= check_rendered_pixel(win, app)
|
||||
win.close()
|
||||
print("ALL PASS" if passed else "FAILED")
|
||||
return 0 if passed else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,7 +1,7 @@
|
||||
# EDID Viewer — 开发需求与进度
|
||||
|
||||
## 基本环境
|
||||
- 主项目位置:`E:\Hulk-Coding\LT8619C_Debug_Tools\EDID-viewer`;为兼容此前约定,已同步镜像到 `E:\Hulk-Coding\LT8619C\_Debug\_Tools\EDID-viewer`。
|
||||
- 主项目位置:`E:\Hulk-Coding\HW-Debug-Tools\EDID-viewer`;为兼容此前约定,已同步镜像到 `E:\Hulk-Coding\LT8619C\_Debug\_Tools\EDID-viewer`。
|
||||
- Windows 10/11 x64;Python 3.14;PySide6 6.11.2(Qt 官方 Python 绑定);PySide6-Fluent-Widgets 1.11.3。
|
||||
- 使用项目 `.venv`;依赖见 requirements.txt;GUI 入口为 `src/main.py`(版本号在 `src/main.py` 的 `APP_VERSION`)。
|
||||
- 独立工具,不依赖、不修改 LT8619C 固件或 DLPilot 工程。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Windows 10/11 显示器 EDID 查看器。使用 **PySide6 / PySide6-Fluent-Widgets**,只读,不修改显示设置。
|
||||
|
||||
> 只想使用工具:到 [Gitea Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases)
|
||||
> 只想使用工具:到 [Gitea Releases](https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases)
|
||||
> 下载 `EDID-Viewer-vX.Y.Z-win64.zip`,解压双击 `EDID-Viewer.exe` 即可(Windows 10/11 x64,免安装、无需 Python)。
|
||||
|
||||
## 使用
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Windows 10/11 显示器 EDID 查看器。使用 **PySide6 / PySide6-Fluent-Widgets**,只读,不修改显示设置。
|
||||
|
||||
> 只想使用工具:到 [Gitea Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases)
|
||||
> 只想使用工具:到 [Gitea Releases](https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases)
|
||||
> 下载 `EDID-Viewer-vX.Y.Z-win64.zip`,解压双击 `EDID-Viewer.exe` 即可(Windows 10/11 x64,免安装、无需 Python)。
|
||||
|
||||
## 使用
|
||||
|
||||
@@ -41,7 +41,7 @@ from windows_edid import scan
|
||||
|
||||
APP_NAME = "EDID Viewer"
|
||||
APP_VERSION = "0.1.0"
|
||||
REPO_URL = "https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools"
|
||||
REPO_URL = "https://gitea.hulk.wang/hulk/HW-Debug-Tools"
|
||||
|
||||
|
||||
def icon_path():
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# LT8619C_Debug_Tools
|
||||
# HW-Debug-Tools
|
||||
|
||||
LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板调试配套上位机工具集。
|
||||
硬件调试上位机工具集,起家于 LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板调试配套,
|
||||
现收纳全部调试工具;原名 `LT8619C_Debug_Tools`,2026-09-28 更名(Gitea 旧地址自动重定向)。
|
||||
上游主仓库(固件):[LT8619C_DLPC3421_HDMI](https://gitea.hulk.wang/hulk/LT8619C_DLPC3421_HDMI)。
|
||||
|
||||
## 工具一览
|
||||
|
||||
| 工具 | 用途 | 获取 |
|
||||
|---|---|---|
|
||||
| [DLPilot](DLPilot/) | HDMI 源端(EDID 查看/逐字节解析、分辨率切换、纯色与测试图案全屏投屏)+ 光机控制(RS485→GD32 网关→DLPC3421:开关光机/设光强/查温度电流) | 到 [Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases) 下 `DLPilot-vX.Y.Z-win64.zip`,解压即用;详见 [DLPilot/README.md](DLPilot/README.md) |
|
||||
| [EDID-viewer](EDID-viewer/) | Windows 显示器 EDID 只读查看器:活动设备或离线文件的厂家/序列号/分辨率时序、CTA/HDMI/音频/HDR 能力、校验诊断;BIN/HEX 导入,BIN/JSON 报告导出 | 到 [Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases) 下 `EDID-Viewer-vX.Y.Z-win64.zip`,解压即用;详见 [EDID-viewer/README.md](EDID-viewer/README.md) |
|
||||
| [SerialMate](SerialMate/) | RS485/串口调试助手:收发 + 协议包解析(帧构成令牌序列/包头/板ID/LEN口径/CRC 全可定制,默认兼容 DLPilot 光机协议)、板型档案一键切换协议参数与命令预设、payload 字符串/HEX 显示、4 通道曲线(弹窗独立、时间窗滑笔回看、悬停读值、暂停渲染)、发送框输入 payload 自动包装组帧(`/` 分隔多条)、HEX 直发与周期发送 | 到 [Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases) 下 `SerialMate-vX.Y.Z-win64.zip`,解压即用;详见 [SerialMate/README.md](SerialMate/README.md) |
|
||||
| [I2C-Inject](I2C-Inject/) | ⏸ **暂停开发**:LT8619C 寄存器在线读写(RP2040 注入器在 demo 板 I2C 总线上择机注入,避让主控轮询,写后自动读回校验)。代码与固件保留备查 | 暂不提供发布;状态与原理详见 [I2C-Inject/README.md](I2C-Inject/README.md) |
|
||||
| 图标 | 工具 | 用途 | 获取 |
|
||||
|---|---|---|---|
|
||||
| <img src="DLPilot/src/logos/logo_dlpilot.png" width="64" alt="DLPilot 图标"/> | [DLPilot](DLPilot/) | HDMI 源端(EDID 查看/逐字节解析、分辨率切换、纯色与测试图案全屏投屏)+ 光机控制(RS485→GD32 网关→DLPC3421:开关光机/设光强/查温度电流) | 到 [Releases](https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases) 下 `DLPilot-vX.Y.Z-win64.zip`,解压即用;详见 [DLPilot/README.md](DLPilot/README.md) |
|
||||
| <img src="EDID-viewer/assets/edid-viewer.png" width="64" alt="EDID-Viewer 图标"/> | [EDID-viewer](EDID-viewer/) | Windows 显示器 EDID 只读查看器:活动设备或离线文件的厂家/序列号/分辨率时序、CTA/HDMI/音频/HDR 能力、校验诊断;BIN/HEX 导入,BIN/JSON 报告导出 | 到 [Releases](https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases) 下 `EDID-Viewer-vX.Y.Z-win64.zip`,解压即用;详见 [EDID-viewer/README.md](EDID-viewer/README.md) |
|
||||
| <img src="SerialMate/assets/serial-mate.png" width="64" alt="SerialMate 图标"/> | [SerialMate](SerialMate/) | RS485/串口调试助手:收发 + 协议包解析(帧构成令牌序列/包头/板ID/LEN口径/CRC 全可定制,默认兼容 DLPilot 光机协议)、板型档案一键切换协议参数与命令预设、payload 字符串/HEX 显示、4 通道曲线(弹窗独立、时间窗滑笔回看、悬停读值、暂停渲染)、发送框输入 payload 自动包装组帧(`/` 分隔多条)、HEX 直发与周期发送 | 到 [Releases](https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases) 下 `SerialMate-vX.Y.Z-win64.zip`,解压即用;详见 [SerialMate/README.md](SerialMate/README.md) |
|
||||
| <img src="I2C-Inject/logos/logo_i2c_orange.png" width="64" alt="I2C-Inject 图标"/> | [I2C-Inject](I2C-Inject/) | ⏸ **暂停开发**:LT8619C 寄存器在线读写(RP2040 注入器在 demo 板 I2C 总线上择机注入,避让主控轮询,写后自动读回校验)。代码与固件保留备查 | 暂不提供发布;状态与原理详见 [I2C-Inject/README.md](I2C-Inject/README.md) |
|
||||
|
||||
## 环境要求
|
||||
|
||||
@@ -30,7 +31,7 @@ LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板调试配套上位机工
|
||||
仓库整体的开发需求与进度管理见根目录 `agent.md`。
|
||||
|
||||
```
|
||||
LT8619C_Debug_Tools/
|
||||
HW-Debug-Tools/
|
||||
├── DLPilot/
|
||||
│ ├── src/ # 源码 + 打包/发布脚本 + 图标源
|
||||
│ ├── assets/ # 生成的测试图案 PNG(gen_*.py 产物)
|
||||
@@ -69,4 +70,4 @@ python publish_gitea.py <工具>-v<版本>-win64.zip --insecure # 上传 Gite
|
||||
- 源码与打包产物(exe、pattern_slots.json)均入库;发布 zip 不入库,只上传 Gitea Release
|
||||
- 两件工具的寄存器语义(0x606E 位交换 / 0x606D 整组顺序)均经 demo 板逻辑分析仪
|
||||
双色交叉实测,过程数据与规程存于上游主仓库 `doc/architecture/`
|
||||
- 更新:2026-09-27
|
||||
- 更新:2026-09-28
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## 1. 项目定位
|
||||
|
||||
仓库 `LT8619C_Debug_Tools` 是 LT8619C→DLPC3421 投影转接板的调试上位机工具集。
|
||||
仓库 `HW-Debug-Tools` 是 LT8619C→DLPC3421 投影转接板的调试上位机工具集。
|
||||
SerialMate 是其中的**通用串口/RS485 调试助手**:收发 + 协议解析 + 曲线。
|
||||
默认帧格式与 DLPilot 光机 RS485 协议完全一致(`D5 01 LEN <payload> CRC`),
|
||||
可直接调试板载 GD32E230 网关;帧格式(包头/板ID/CRC 算法与覆盖范围)可定制,
|
||||
|
||||
@@ -1,35 +1,62 @@
|
||||
"""生成 SerialMate 图标(Pillow, 开发时手动运行): 蓝底白色波形 + RS485 字样"""
|
||||
from pathlib import Path
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
SerialMate 图标栅格化(家族风格, 与 DLPilot/EDID-Viewer/FlashTool 同版式):
|
||||
黑底 512, 绿色圆角矩形, 第一行 Serial(框内黑字), 第二行 Mate(白字)
|
||||
================================================================
|
||||
设计参数: 黑底 512, 绿色圆角矩形 x38 y64 w436 h186 rx34 (#00C878, 与
|
||||
gd32e230f8_firmware_merge_tool 的 FlashTool 同色系), Arial Bold。
|
||||
Serial 6 字母按框宽自适应字号(上限 146px, 留边距),
|
||||
Mate 146px 白字(基线对齐同 DLPilot 的 Pilot)。
|
||||
|
||||
用法: python make_icon.py # 生成 serial-mate.png / serial-mate.ico
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
out = Path(__file__).resolve().parent
|
||||
size = 512
|
||||
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
||||
BASE = os.path.dirname(os.path.abspath(__file__))
|
||||
FONT = r'C:\Windows\Fonts\arialbd.ttf' # Arial Bold, Windows 标配
|
||||
|
||||
|
||||
def fit_font(draw, text, max_w, start):
|
||||
"""从 start 字号往下找能装入 max_w 宽的字号(步进 2)"""
|
||||
size = start
|
||||
while size > 8:
|
||||
f = ImageFont.truetype(FONT, size)
|
||||
box = draw.textbbox((0, 0), text, font=f)
|
||||
if box[2] - box[0] <= max_w:
|
||||
return f
|
||||
size -= 2
|
||||
return ImageFont.truetype(FONT, 8)
|
||||
|
||||
|
||||
def render(size=512):
|
||||
s = size / 512.0
|
||||
img = Image.new('RGB', (size, size), (0, 0, 0))
|
||||
d = ImageDraw.Draw(img)
|
||||
d.rounded_rectangle((24, 24, 488, 488), radius=96, fill='#0f6cbd')
|
||||
d.rounded_rectangle((24, 24, 488, 488), radius=96, outline='#5ab0f2', width=10)
|
||||
d.rounded_rectangle([38 * s, 64 * s, (38 + 436) * s, (64 + 186) * s],
|
||||
radius=34 * s, fill=(0, 200, 120))
|
||||
if not os.path.exists(FONT):
|
||||
raise SystemExit(f'未找到字体 {FONT}, 无法栅格化')
|
||||
# Serial: 黑字居中于橙色框, 按框宽自适应(留 2×18px 边距)
|
||||
f1 = fit_font(d, 'Serial', 400 * s, round(146 * s))
|
||||
d.text((size / 2, 64 * s + 186 * s / 2), 'Serial', font=f1,
|
||||
fill=(0, 0, 0), anchor='mm')
|
||||
# Mate: 白字, 与家族一致 146px(无下伸字母, 中心 = 基线421 - cap/2 ~= 368)
|
||||
f2 = ImageFont.truetype(FONT, max(8, round(146 * s)))
|
||||
d.text((size / 2, 368 * s), 'Mate', font=f2, fill=(255, 255, 255),
|
||||
anchor='mm')
|
||||
return img
|
||||
|
||||
# 示波器式白色波形(锯齿+衰减循环, 手绘点位)
|
||||
wave = [(56, 268)]
|
||||
segs = ((46, -96), (40, 84), (52, -52), (38, 66), (60, -120), (44, 78),
|
||||
(50, -40), (42, 56), (56, -88), (44, 60))
|
||||
x, y = 56, 268
|
||||
for half, dy in segs:
|
||||
d.line((x, y, x + half // 2, y + dy), fill='white', width=20)
|
||||
d.line((x + half // 2, y + dy, x + half, y), fill='white', width=20)
|
||||
x, y = x + half, y
|
||||
d.ellipse((x - 10, y - 10, x + 10, y + 10), fill='white')
|
||||
|
||||
# 顶部 TX/RX 指示点
|
||||
for cx, color in ((88, '#ffd166'), (146, '#7ee081')):
|
||||
d.ellipse((cx - 17, 84 - 17, cx + 17, 84 + 17), fill=color)
|
||||
|
||||
font = 'C:/Windows/Fonts/arialbd.ttf'
|
||||
d.text((256, 410), 'RS485', font=ImageFont.truetype(font, 72),
|
||||
anchor='mm', fill='white')
|
||||
img.save(out / 'serial-mate.png')
|
||||
img.save(out / 'serial-mate.ico',
|
||||
sizes=[(16, 16), (24, 24), (32, 32), (48, 48), (64, 64),
|
||||
(128, 128), (256, 256)])
|
||||
print('icon ->', out / 'serial-mate.ico')
|
||||
if __name__ == '__main__':
|
||||
img = render(512)
|
||||
png = os.path.join(BASE, 'serial-mate.png')
|
||||
ico = os.path.join(BASE, 'serial-mate.ico')
|
||||
img.save(png)
|
||||
img.save(ico, sizes=[(16, 16), (24, 24), (32, 32), (48, 48),
|
||||
(64, 64), (128, 128), (256, 256)])
|
||||
print(f'写出 {png}')
|
||||
print(f'写出 {ico}')
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 16 KiB |
@@ -50,7 +50,7 @@ from theme import ThemeManager
|
||||
|
||||
APP_NAME = 'SerialMate'
|
||||
APP_VERSION = '0.1.0'
|
||||
REPO_URL = 'https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools'
|
||||
REPO_URL = 'https://gitea.hulk.wang/hulk/HW-Debug-Tools'
|
||||
|
||||
BAUDS = (1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600)
|
||||
TX_MODES = ('wrap', 'hex')
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
|
||||
## 1. 项目定位与约定
|
||||
|
||||
- 本仓库是 **LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板**的调试上位机工具集,
|
||||
服务上游固件仓 `hulk/LT8619C_DLPC3421_HDMI`(本机路径
|
||||
- 本仓库是**全部调试工具的收纳仓**(起家于 **LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板**
|
||||
调试配套)。原名 `LT8619C_Debug_Tools`,2026-09-28 更名 `HW-Debug-Tools`:Gitea 已改名
|
||||
(旧地址自动重定向)、本地目录与 remote 同步更名;Gitea Release 同日清理为各已发布工具
|
||||
仅保留最新版(DLPilot v0.4.0 / EDID-Viewer v0.1.0 / SerialMate v0.1.0),
|
||||
旧 release 删除但 tag 与提交历史保留。服务上游固件仓 `hulk/LT8619C_DLPC3421_HDMI`(本机路径
|
||||
`E:\Hulk-Coding\LT8619C_DLPC3421_HDMI`,同 Gitea 实例 gitea.hulk.wang)。
|
||||
光机 RS485 协议**唯一权威**是上游仓 `protocols.md`,本仓不维护协议副本。
|
||||
- 工具链(全仓统一):Python 3.14;GUI 用 PySide6 + PySide6-Fluent-Widgets,解析/协议
|
||||
@@ -26,7 +29,7 @@
|
||||
自动包装发送。
|
||||
- **I2C-Inject**:RP2040 固件 + PC GUI,demo 板 I2C 总线择机注入读写寄存器。
|
||||
**2026-09-25 起暂停开发**,代码与固件保留备查。
|
||||
- 镜像约定:`EDID-viewer` 主目录(`E:\Hulk-Coding\LT8619C_Debug_Tools\EDID-viewer`)
|
||||
- 镜像约定:`EDID-viewer` 主目录(`E:\Hulk-Coding\HW-Debug-Tools\EDID-viewer`)
|
||||
改动后需 robocopy /MIR 同步到 `E:\Hulk-Coding\LT8619C\_Debug\_Tools\EDID-viewer`
|
||||
(排除 .venv/build/__pycache__/.git,zip 不同步)。
|
||||
- 发布约定:源码与打包产物(exe、运行配置)入库;发布 zip 不入库,只上传 Gitea Release。
|
||||
@@ -62,6 +65,8 @@
|
||||
- **更名**:原名 SerialAssistant(目录/exe/文档/配置同步更名;旧配置
|
||||
serial_assistant.json 首次启动自动迁移为 serial_mate.json;图标与名字
|
||||
无绑定为波形+RS485 母题)。用户确认 "SerialMate 吧"(2026-09-27)。
|
||||
- **已发布**:commit d133906 推送 main 并打 tag `SerialMate-v0.1.0`,
|
||||
Release 附件 `SerialMate-v0.1.0-win64.zip`(63.7 MB)已上传核对。
|
||||
- 协议:**帧构成令牌序列可定制**(`HDR ID LEN PAYLOAD CRC` + 十六进制字面量
|
||||
同步头,收发共用布局仅包头分方向;支持字段换序/无板ID/多字节同步头,LEN
|
||||
口径 payload 长度/到帧尾/整帧三种)、5 种 CRC 算法 × 3 种覆盖范围,默认与
|
||||
|
||||
Reference in New Issue
Block a user