feat: 产品更名 DLPilot(3D 光固化光机调试台) + 按标记调整界面
This commit is contained in:
@@ -9,6 +9,7 @@ dist/
|
|||||||
|
|
||||||
# 发布 zip: 可由 src/package_release.py 重新生成, 只上传 Gitea Release
|
# 发布 zip: 可由 src/package_release.py 重新生成, 只上传 Gitea Release
|
||||||
HDMI-Tool/release/*.zip
|
HDMI-Tool/release/*.zip
|
||||||
|
DLPilot/release/*.zip
|
||||||
|
|
||||||
# ZCode 客户端本地会话数据(计划留档等), 非项目配置
|
# ZCode 客户端本地会话数据(计划留档等), 非项目配置
|
||||||
.zcode/
|
.zcode/
|
||||||
|
|||||||
+13
-13
@@ -1,4 +1,4 @@
|
|||||||
# AGENTS.md — HDMI-Tool 工程档案(供 AI/Agent 使用)
|
# AGENTS.md — DLPilot 工程档案(供 AI/Agent 使用)
|
||||||
|
|
||||||
> **本文档面向 AI/Agent**,是人类文档 [README.md](README.md) 的姊妹篇,两者不重叠:
|
> **本文档面向 AI/Agent**,是人类文档 [README.md](README.md) 的姊妹篇,两者不重叠:
|
||||||
> README 回答"这是什么、怎么用";本文回答"代码怎么组织、怎么构建发布、改动时哪些约束不能破坏"。
|
> README 回答"这是什么、怎么用";本文回答"代码怎么组织、怎么构建发布、改动时哪些约束不能破坏"。
|
||||||
@@ -9,17 +9,17 @@
|
|||||||
仓库 `LT8619C_Debug_Tools` 是 LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板的**调试上位机工具集**,
|
仓库 `LT8619C_Debug_Tools` 是 LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板的**调试上位机工具集**,
|
||||||
上游主仓库(固件)为 `hulk/LT8619C_DLPC3421_HDMI`(同 Gitea 实例 `gitea.hulk.wang`),
|
上游主仓库(固件)为 `hulk/LT8619C_DLPC3421_HDMI`(同 Gitea 实例 `gitea.hulk.wang`),
|
||||||
本仓库本机路径 `E:\Hulk-Coding\LT8619C_DLPC3421_HDMI`。
|
本仓库本机路径 `E:\Hulk-Coding\LT8619C_DLPC3421_HDMI`。
|
||||||
HDMI-Tool 工作在两端:HDMI **源端**(PC 显卡侧,EDID/分辨率/图案)与**光机控制端**
|
DLPilot 工作在两端:HDMI **源端**(PC 显卡侧,EDID/分辨率/图案)与**光机控制端**
|
||||||
(RS485 → 板载 GD32E230 网关 → DLPC3421)。寄存器语义判读基线(0x606E 位交换 /
|
(RS485 → 板载 GD32E230 网关 → DLPC3421)。寄存器语义判读基线(0x606E 位交换 /
|
||||||
0x606D 整组顺序)与光机协议规程都在上游仓库 `doc/architecture/` 与 `protocols.md`,不在本仓库。
|
0x606D 整组顺序)与光机协议规程都在上游仓库 `doc/architecture/` 与 `protocols.md`,不在本仓库。
|
||||||
|
|
||||||
## 2. 目录契约(重要)
|
## 2. 目录契约(重要)
|
||||||
|
|
||||||
```
|
```
|
||||||
HDMI-Tool/
|
DLPilot/
|
||||||
├── src/ 源代码区 —— 只有这里可以手改(logos/ 改图标源后重跑 make_ico.py)
|
├── src/ 源代码区 —— 只有这里可以手改(logos/ 改图标源后重跑 make_ico.py)
|
||||||
├── assets/ 生成资产区 —— gen_*.py 的产物(PNG 图案),可随时再生成,改动需提交
|
├── assets/ 生成资产区 —— gen_*.py 的产物(PNG 图案),可随时再生成,改动需提交
|
||||||
├── release/ 产物区 —— 机器生成,禁止手改:HDMI-Tool.exe、pattern_slots.json、
|
├── release/ 产物区 —— 机器生成,禁止手改:DLPilot.exe、pattern_slots.json、
|
||||||
│ bw/solid 图案(package_release.py 从 assets/ 平铺复制来,均入库)、
|
│ bw/solid 图案(package_release.py 从 assets/ 平铺复制来,均入库)、
|
||||||
│ *.zip(gitignore,只上传 Release)。release/ 本身=完整可直接运行的
|
│ *.zip(gitignore,只上传 Release)。release/ 本身=完整可直接运行的
|
||||||
│ 发布文件夹(exe+附属平铺),内容与 zip 一致
|
│ 发布文件夹(exe+附属平铺),内容与 zip 一致
|
||||||
@@ -42,8 +42,8 @@ HDMI-Tool/
|
|||||||
| `src/config.py` | 运行目录定位(BASE_DIR)与 pattern_slots.json 读写(slots/area/serial 三键) |
|
| `src/config.py` | 运行目录定位(BASE_DIR)与 pattern_slots.json 读写(slots/area/serial 三键) |
|
||||||
| `src/dlpc_rs485.py` | 光机 RS485 协议模块: 帧构造/增量解析/译码表/预设命令/串口线程(DLPC485) |
|
| `src/dlpc_rs485.py` | 光机 RS485 协议模块: 帧构造/增量解析/译码表/预设命令/串口线程(DLPC485) |
|
||||||
| `src/selftest_rs485.py` | 光机协议自检(对照上游实测帧向量, 无硬件回归, 改协议代码后必跑) |
|
| `src/selftest_rs485.py` | 光机协议自检(对照上游实测帧向量, 无硬件回归, 改协议代码后必跑) |
|
||||||
| `src/build_exe.py` | PyInstaller 打包 → `release/HDMI-Tool.exe`(onefile/noconsole, 内嵌图标+pyserial+customtkinter) |
|
| `src/build_exe.py` | PyInstaller 打包 → `release/DLPilot.exe`(onefile/noconsole, 内嵌图标+pyserial+customtkinter) |
|
||||||
| `src/package_release.py` | 复制图案到 release/(平铺) → `release/HDMI-Tool-v<ver>-win64.zip`(校验栏位引用完整性; release/ 与 zip 内容一致) |
|
| `src/package_release.py` | 复制图案到 release/(平铺) → `release/DLPilot-v<ver>-win64.zip`(校验栏位引用完整性; release/ 与 zip 内容一致) |
|
||||||
| `src/publish_gitea.py` | 建/复用 Gitea Release 并上传 zip(tag 默认取 zip 文件名) |
|
| `src/publish_gitea.py` | 建/复用 Gitea Release 并上传 zip(tag 默认取 zip 文件名) |
|
||||||
| `src/hdmi_source.ps1/.bat` | 独立 PowerShell 命令行工具(自包含,与 GUI 无代码共享) |
|
| `src/hdmi_source.ps1/.bat` | 独立 PowerShell 命令行工具(自包含,与 GUI 无代码共享) |
|
||||||
| `src/gen_bw_patterns.py` | 生成 `assets/bw_*.png` ×5(640x360 黑白,需 Pillow) |
|
| `src/gen_bw_patterns.py` | 生成 `assets/bw_*.png` ×5(640x360 黑白,需 Pillow) |
|
||||||
@@ -87,7 +87,7 @@ HDMI-Tool/
|
|||||||
纯数组(无 area)与无 serial 键两种历史格式,save 永远写全三键。`serial` 子键为
|
纯数组(无 area)与无 serial 键两种历史格式,save 永远写全三键。`serial` 子键为
|
||||||
`{port, baud, bytesize(8/7/6/5), parity(N/E/O), stopbits(1/2)}`,旧配置缺子键按
|
`{port, baud, bytesize(8/7/6/5), parity(N/E/O), stopbits(1/2)}`,旧配置缺子键按
|
||||||
默认 8-N-1 补齐。
|
默认 8-N-1 补齐。
|
||||||
12. **GUI = app_gui.py 双栏仪表盘**(规格:`HDMI-Tool/UI参考布局.svg`):左列 HDMI 源端
|
12. **GUI = app_gui.py 双栏仪表盘**(规格:`DLPilot/UI参考布局.svg`):左列 HDMI 源端
|
||||||
五卡(显示器/模式/EDID 信息/测试图案/hex),右列光机四卡(串口/数据/命令/滑条),
|
五卡(显示器/模式/EDID 信息/测试图案/hex),右列光机四卡(串口/数据/命令/滑条),
|
||||||
顶栏 Dark/Light/System 切换(ttk.Treeview 颜色随动)。打包必须 `--collect-all
|
顶栏 Dark/Light/System 切换(ttk.Treeview 颜色随动)。打包必须 `--collect-all
|
||||||
customtkinter`(build_exe.py 已内置,勿删)——CTk 主题/字体数据缺失会让 exe 启动即崩。
|
customtkinter`(build_exe.py 已内置,勿删)——CTk 主题/字体数据缺失会让 exe 启动即崩。
|
||||||
@@ -111,14 +111,14 @@ HDMI-Tool/
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
python gen_bw_patterns.py ; python gen_solid_colors.py # 仅当改了图案生成逻辑
|
python gen_bw_patterns.py ; python gen_solid_colors.py # 仅当改了图案生成逻辑
|
||||||
python build_exe.py # → ../release/HDMI-Tool.exe(缺 PyInstaller 会自动 pip install)
|
python build_exe.py # → ../release/DLPilot.exe(缺 PyInstaller 会自动 pip install)
|
||||||
python build_exe.py --debug # 附加带控制台的 HDMI-Tool-console.exe(调试 --dump 用)
|
python build_exe.py --debug # 附加带控制台的 DLPilot-console.exe(调试 --dump 用)
|
||||||
python package_release.py <版本> # → ../release/HDMI-Tool-v<版本>-win64.zip
|
python package_release.py <版本> # → ../release/DLPilot-v<版本>-win64.zip
|
||||||
python publish_gitea.py HDMI-Tool-v<版本>-win64.zip --replace --insecure # 上传(需 GITEA_TOKEN)
|
python publish_gitea.py DLPilot-v<版本>-win64.zip --replace --insecure # 上传(需 GITEA_TOKEN)
|
||||||
```
|
```
|
||||||
|
|
||||||
发布约定:
|
发布约定:
|
||||||
- tag/release 命名 `HDMI-Tool-vX.Y.Z`,zip 命名 `HDMI-Tool-vX.Y.Z-win64.zip`(publish_gitea.py
|
- tag/release 命名 `DLPilot-vX.Y.Z`,zip 命名 `DLPilot-vX.Y.Z-win64.zip`(publish_gitea.py
|
||||||
依赖此命名从文件名推 tag);
|
依赖此命名从文件名推 tag);
|
||||||
- **exe、pattern_slots.json 与 release/ 下平铺的图案 png 改动跟随源码/资产生成提交入库;
|
- **exe、pattern_slots.json 与 release/ 下平铺的图案 png 改动跟随源码/资产生成提交入库;
|
||||||
zip 永不入库**(.gitignore 已挡);
|
zip 永不入库**(.gitignore 已挡);
|
||||||
@@ -151,5 +151,5 @@ python publish_gitea.py HDMI-Tool-v<版本>-win64.zip --replace --insecure #
|
|||||||
4. `python hdmi_gui.py --test-pattern Checker --area 800x600 --seconds 3` —— 投图链路;
|
4. `python hdmi_gui.py --test-pattern Checker --area 800x600 --seconds 3` —— 投图链路;
|
||||||
5. `python hdmi_gui.py --dump` —— EDID 解算不抛异常;
|
5. `python hdmi_gui.py --dump` —— EDID 解算不抛异常;
|
||||||
6. `python hdmi_gui.py --dlpc-cmd M999`(不带 --port)—— 应明确报错而非崩溃(无硬件时的优雅降级);
|
6. `python hdmi_gui.py --dlpc-cmd M999`(不带 --port)—— 应明确报错而非崩溃(无硬件时的优雅降级);
|
||||||
7. `python build_exe.py` → 双击 release/HDMI-Tool.exe 确认图标/双栏布局/投图/光机区渲染;
|
7. `python build_exe.py` → 双击 release/DLPilot.exe 确认图标/双栏布局/投图/光机区渲染;
|
||||||
8. `python package_release.py <版本>` —— 不报"引用图片缺失"即栏位完整性 OK。
|
8. `python package_release.py <版本>` —— 不报"引用图片缺失"即栏位完整性 OK。
|
||||||
|
|||||||
+13
-13
@@ -1,11 +1,11 @@
|
|||||||
# HDMI-Tool — HDMI 源端调试 + 光机控制工具
|
# DLPilot — HDMI 源端调试 + 光机控制工具
|
||||||
|
|
||||||
> LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板调试配套的 PC 端工具:
|
> LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板调试配套的 PC 端工具:
|
||||||
> HDMI **源端**(EDID 查看、分辨率切换、纯色/测试图案投屏)+ **光机控制**
|
> HDMI **源端**(EDID 查看、分辨率切换、纯色/测试图案投屏)+ **光机控制**
|
||||||
> (RS485 直连板上 GD32 网关,开关光机/设光强/查温度电流)。
|
> (RS485 直连板上 GD32 网关,开关光机/设光强/查温度电流)。
|
||||||
>
|
>
|
||||||
> - **只想用工具**:到 [Gitea Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases)
|
> - **只想用工具**:到 [Gitea Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases)
|
||||||
> 下载 `HDMI-Tool-vX.Y.Z-win64.zip`,解压双击 `HDMI-Tool.exe` 即可(Windows 10/11 x64,免安装、无需 Python)。
|
> 下载 `DLPilot-vX.Y.Z-win64.zip`,解压双击 `DLPilot.exe` 即可(Windows 10/11 x64,免安装、无需 Python)。
|
||||||
> - **要改代码/重新打包**:见 §8、§9。
|
> - **要改代码/重新打包**:见 §8、§9。
|
||||||
>
|
>
|
||||||
> 更新:2026-09-11
|
> 更新:2026-09-11
|
||||||
@@ -29,15 +29,15 @@
|
|||||||
## 2. 下载与安装
|
## 2. 下载与安装
|
||||||
|
|
||||||
1. 打开 [Releases 页面](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases),取最新的
|
1. 打开 [Releases 页面](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases),取最新的
|
||||||
`HDMI-Tool-vX.Y.Z-win64.zip`;
|
`DLPilot-vX.Y.Z-win64.zip`;
|
||||||
2. 解压到**任意可写目录**(自定义图片与栏位配置会写到 exe 旁边);
|
2. 解压到**任意可写目录**(自定义图片与栏位配置会写到 exe 旁边);
|
||||||
3. 双击 `HDMI-Tool.exe`。首次启动比脚本慢一两秒(onefile 解压),属正常现象。
|
3. 双击 `DLPilot.exe`。首次启动比脚本慢一两秒(onefile 解压),属正常现象。
|
||||||
|
|
||||||
包内包含:
|
包内包含:
|
||||||
|
|
||||||
```
|
```
|
||||||
HDMI-Tool/
|
DLPilot/
|
||||||
├── HDMI-Tool.exe 主程序(单文件自包含, 光机控制的 pyserial 已内置)
|
├── DLPilot.exe 主程序(单文件自包含, 光机控制的 pyserial 已内置)
|
||||||
├── pattern_slots.json 预置自定义栏位 + 串口记忆
|
├── pattern_slots.json 预置自定义栏位 + 串口记忆
|
||||||
├── bw_*.png ×5 640x360 黑白测试图
|
├── bw_*.png ×5 640x360 黑白测试图
|
||||||
├── solid_*.png ×10 800x600 纯色测试图
|
├── solid_*.png ×10 800x600 纯色测试图
|
||||||
@@ -72,7 +72,7 @@ HDMI-Tool/
|
|||||||
## 4. 典型测试场景
|
## 4. 典型测试场景
|
||||||
|
|
||||||
```
|
```
|
||||||
1. HDMI 接转接板 → 启动 HDMI-Tool → 刷新 → 选中板卡显示器
|
1. HDMI 接转接板 → 启动 DLPilot → 刷新 → 选中板卡显示器
|
||||||
2. 板卡 shadow EDID 首选 640x360@60 → 测试卡区域选 640x360(与光机面板原生 1:1)
|
2. 板卡 shadow EDID 首选 640x360@60 → 测试卡区域选 640x360(与光机面板原生 1:1)
|
||||||
3. "光机控制"连接串口 → M999 查版本确认链路通 → M730S0 开光机
|
3. "光机控制"连接串口 → M999 查版本确认链路通 → M730S0 开光机
|
||||||
4. 点 R/G/B 行纯色按钮投图 → 目视/逻辑分析仪核对 RGB888 输出
|
4. 点 R/G/B 行纯色按钮投图 → 目视/逻辑分析仪核对 RGB888 输出
|
||||||
@@ -180,7 +180,7 @@ python la_wave_analyzer3.py <capture.csv> # 3 通道(RGB 三组同拍, ch8/
|
|||||||
## 8. 目录结构与从源码运行
|
## 8. 目录结构与从源码运行
|
||||||
|
|
||||||
```
|
```
|
||||||
HDMI-Tool/
|
DLPilot/
|
||||||
├── src/ # 源代码(人工维护区)
|
├── src/ # 源代码(人工维护区)
|
||||||
│ ├── hdmi_gui.py # 入口与命令行模式(argparse 分发)
|
│ ├── hdmi_gui.py # 入口与命令行模式(argparse 分发)
|
||||||
│ ├── app_gui.py # CustomTkinter 主界面(双栏仪表盘)
|
│ ├── app_gui.py # CustomTkinter 主界面(双栏仪表盘)
|
||||||
@@ -202,7 +202,7 @@ HDMI-Tool/
|
|||||||
│ ├── bw_*.png ×5 # 640x360 黑白系列
|
│ ├── bw_*.png ×5 # 640x360 黑白系列
|
||||||
│ └── solid_*.png ×10 # 800x600 纯色系列
|
│ └── solid_*.png ×10 # 800x600 纯色系列
|
||||||
├── release/ # 构建与发布产物(机器生成区, 不手改)
|
├── release/ # 构建与发布产物(机器生成区, 不手改)
|
||||||
│ ├── HDMI-Tool.exe # 打包单文件版(改动跟随源码提交入库)
|
│ ├── DLPilot.exe # 打包单文件版(改动跟随源码提交入库)
|
||||||
│ ├── pattern_slots.json # exe 运行配置(栏位预置 + 串口记忆)
|
│ ├── pattern_slots.json # exe 运行配置(栏位预置 + 串口记忆)
|
||||||
│ ├── *.png / README.md # 附属文件平铺副本(由 package_release.py 从 assets/ 同步)
|
│ ├── *.png / README.md # 附属文件平铺副本(由 package_release.py 从 assets/ 同步)
|
||||||
│ └── *.zip # 发布包(不入库, 上传 Gitea Release)
|
│ └── *.zip # 发布包(不入库, 上传 Gitea Release)
|
||||||
@@ -220,11 +220,11 @@ GUI 需 customtkinter(`py -m pip install customtkinter`);光机控制需 p
|
|||||||
```powershell
|
```powershell
|
||||||
cd src
|
cd src
|
||||||
python selftest_rs485.py # 光机协议回归(改 dlpc_rs485.py 后必跑)
|
python selftest_rs485.py # 光机协议回归(改 dlpc_rs485.py 后必跑)
|
||||||
python build_exe.py # 打包 → ../release/HDMI-Tool.exe(自动装 PyInstaller;
|
python build_exe.py # 打包 → ../release/DLPilot.exe(自动装 PyInstaller;
|
||||||
# 内置 pyserial/customtkinter, CTk 主题数据自动收集)
|
# 内置 pyserial/customtkinter, CTk 主题数据自动收集)
|
||||||
python build_exe.py --debug # 额外出一个带控制台的调试变体(--dump 可见输出)
|
python build_exe.py --debug # 额外出一个带控制台的调试变体(--dump 可见输出)
|
||||||
python package_release.py 0.2.0 # 组装 release/HDMI-Tool-v0.2.0-win64.zip
|
python package_release.py 0.2.0 # 组装 release/DLPilot-v0.2.0-win64.zip
|
||||||
python publish_gitea.py HDMI-Tool-v0.2.0-win64.zip --insecure # 上传 Gitea Release(需 GITEA_TOKEN)
|
python publish_gitea.py DLPilot-v0.2.0-win64.zip --insecure # 上传 Gitea Release(需 GITEA_TOKEN)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 10. 注意事项 / FAQ
|
## 10. 注意事项 / FAQ
|
||||||
@@ -235,6 +235,6 @@ python publish_gitea.py HDMI-Tool-v0.2.0-win64.zip --insecure # 上传 Gitea R
|
|||||||
- **exe 放只读目录会怎样**:自定义图片与 `pattern_slots.json` 写在 exe 旁边,只读目录会导致配置存不下;
|
- **exe 放只读目录会怎样**:自定义图片与 `pattern_slots.json` 写在 exe 旁边,只读目录会导致配置存不下;
|
||||||
- **重新打包后图标没变**:Windows 图标缓存,`ie4uinit -show` 或改个名即可;
|
- **重新打包后图标没变**:Windows 图标缓存,`ie4uinit -show` 或改个名即可;
|
||||||
- **多屏序号**:切分辨率前先确认显示器序号(GUI 下拉框与 `hdmi_source.bat -List` 输出一致);
|
- **多屏序号**:切分辨率前先确认显示器序号(GUI 下拉框与 `hdmi_source.bat -List` 输出一致);
|
||||||
- **残留进程**:修改源码重新打包前先结束残留的 HDMI-Tool 进程(`build_exe.py` 会自动 taskkill);
|
- **残留进程**:修改源码重新打包前先结束残留的 DLPilot 进程(`build_exe.py` 会自动 taskkill);
|
||||||
- **改 logo**:改 `src/logos/logo_ph_orange.svg` → `python src/logos/make_ico.py` → 重新打包;
|
- **改 logo**:改 `src/logos/logo_ph_orange.svg` → `python src/logos/make_ico.py` → 重新打包;
|
||||||
- **配置互不影响**:exe 与源码脚本各自按所在目录保存 `pattern_slots.json`,两份安装互不干扰。
|
- **配置互不影响**:exe 与源码脚本各自按所在目录保存 `pattern_slots.json`,两份安装互不干扰。
|
||||||
|
|||||||
Binary file not shown.
+13
-13
@@ -1,11 +1,11 @@
|
|||||||
# HDMI-Tool — HDMI 源端调试 + 光机控制工具
|
# DLPilot — HDMI 源端调试 + 光机控制工具
|
||||||
|
|
||||||
> LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板调试配套的 PC 端工具:
|
> LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板调试配套的 PC 端工具:
|
||||||
> HDMI **源端**(EDID 查看、分辨率切换、纯色/测试图案投屏)+ **光机控制**
|
> HDMI **源端**(EDID 查看、分辨率切换、纯色/测试图案投屏)+ **光机控制**
|
||||||
> (RS485 直连板上 GD32 网关,开关光机/设光强/查温度电流)。
|
> (RS485 直连板上 GD32 网关,开关光机/设光强/查温度电流)。
|
||||||
>
|
>
|
||||||
> - **只想用工具**:到 [Gitea Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases)
|
> - **只想用工具**:到 [Gitea Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases)
|
||||||
> 下载 `HDMI-Tool-vX.Y.Z-win64.zip`,解压双击 `HDMI-Tool.exe` 即可(Windows 10/11 x64,免安装、无需 Python)。
|
> 下载 `DLPilot-vX.Y.Z-win64.zip`,解压双击 `DLPilot.exe` 即可(Windows 10/11 x64,免安装、无需 Python)。
|
||||||
> - **要改代码/重新打包**:见 §8、§9。
|
> - **要改代码/重新打包**:见 §8、§9。
|
||||||
>
|
>
|
||||||
> 更新:2026-09-11
|
> 更新:2026-09-11
|
||||||
@@ -29,15 +29,15 @@
|
|||||||
## 2. 下载与安装
|
## 2. 下载与安装
|
||||||
|
|
||||||
1. 打开 [Releases 页面](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases),取最新的
|
1. 打开 [Releases 页面](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases),取最新的
|
||||||
`HDMI-Tool-vX.Y.Z-win64.zip`;
|
`DLPilot-vX.Y.Z-win64.zip`;
|
||||||
2. 解压到**任意可写目录**(自定义图片与栏位配置会写到 exe 旁边);
|
2. 解压到**任意可写目录**(自定义图片与栏位配置会写到 exe 旁边);
|
||||||
3. 双击 `HDMI-Tool.exe`。首次启动比脚本慢一两秒(onefile 解压),属正常现象。
|
3. 双击 `DLPilot.exe`。首次启动比脚本慢一两秒(onefile 解压),属正常现象。
|
||||||
|
|
||||||
包内包含:
|
包内包含:
|
||||||
|
|
||||||
```
|
```
|
||||||
HDMI-Tool/
|
DLPilot/
|
||||||
├── HDMI-Tool.exe 主程序(单文件自包含, 光机控制的 pyserial 已内置)
|
├── DLPilot.exe 主程序(单文件自包含, 光机控制的 pyserial 已内置)
|
||||||
├── pattern_slots.json 预置自定义栏位 + 串口记忆
|
├── pattern_slots.json 预置自定义栏位 + 串口记忆
|
||||||
├── bw_*.png ×5 640x360 黑白测试图
|
├── bw_*.png ×5 640x360 黑白测试图
|
||||||
├── solid_*.png ×10 800x600 纯色测试图
|
├── solid_*.png ×10 800x600 纯色测试图
|
||||||
@@ -72,7 +72,7 @@ HDMI-Tool/
|
|||||||
## 4. 典型测试场景
|
## 4. 典型测试场景
|
||||||
|
|
||||||
```
|
```
|
||||||
1. HDMI 接转接板 → 启动 HDMI-Tool → 刷新 → 选中板卡显示器
|
1. HDMI 接转接板 → 启动 DLPilot → 刷新 → 选中板卡显示器
|
||||||
2. 板卡 shadow EDID 首选 640x360@60 → 测试卡区域选 640x360(与光机面板原生 1:1)
|
2. 板卡 shadow EDID 首选 640x360@60 → 测试卡区域选 640x360(与光机面板原生 1:1)
|
||||||
3. "光机控制"连接串口 → M999 查版本确认链路通 → M730S0 开光机
|
3. "光机控制"连接串口 → M999 查版本确认链路通 → M730S0 开光机
|
||||||
4. 点 R/G/B 行纯色按钮投图 → 目视/逻辑分析仪核对 RGB888 输出
|
4. 点 R/G/B 行纯色按钮投图 → 目视/逻辑分析仪核对 RGB888 输出
|
||||||
@@ -180,7 +180,7 @@ python la_wave_analyzer3.py <capture.csv> # 3 通道(RGB 三组同拍, ch8/
|
|||||||
## 8. 目录结构与从源码运行
|
## 8. 目录结构与从源码运行
|
||||||
|
|
||||||
```
|
```
|
||||||
HDMI-Tool/
|
DLPilot/
|
||||||
├── src/ # 源代码(人工维护区)
|
├── src/ # 源代码(人工维护区)
|
||||||
│ ├── hdmi_gui.py # 入口与命令行模式(argparse 分发)
|
│ ├── hdmi_gui.py # 入口与命令行模式(argparse 分发)
|
||||||
│ ├── app_gui.py # CustomTkinter 主界面(双栏仪表盘)
|
│ ├── app_gui.py # CustomTkinter 主界面(双栏仪表盘)
|
||||||
@@ -202,7 +202,7 @@ HDMI-Tool/
|
|||||||
│ ├── bw_*.png ×5 # 640x360 黑白系列
|
│ ├── bw_*.png ×5 # 640x360 黑白系列
|
||||||
│ └── solid_*.png ×10 # 800x600 纯色系列
|
│ └── solid_*.png ×10 # 800x600 纯色系列
|
||||||
├── release/ # 构建与发布产物(机器生成区, 不手改)
|
├── release/ # 构建与发布产物(机器生成区, 不手改)
|
||||||
│ ├── HDMI-Tool.exe # 打包单文件版(改动跟随源码提交入库)
|
│ ├── DLPilot.exe # 打包单文件版(改动跟随源码提交入库)
|
||||||
│ ├── pattern_slots.json # exe 运行配置(栏位预置 + 串口记忆)
|
│ ├── pattern_slots.json # exe 运行配置(栏位预置 + 串口记忆)
|
||||||
│ ├── *.png / README.md # 附属文件平铺副本(由 package_release.py 从 assets/ 同步)
|
│ ├── *.png / README.md # 附属文件平铺副本(由 package_release.py 从 assets/ 同步)
|
||||||
│ └── *.zip # 发布包(不入库, 上传 Gitea Release)
|
│ └── *.zip # 发布包(不入库, 上传 Gitea Release)
|
||||||
@@ -220,11 +220,11 @@ GUI 需 customtkinter(`py -m pip install customtkinter`);光机控制需 p
|
|||||||
```powershell
|
```powershell
|
||||||
cd src
|
cd src
|
||||||
python selftest_rs485.py # 光机协议回归(改 dlpc_rs485.py 后必跑)
|
python selftest_rs485.py # 光机协议回归(改 dlpc_rs485.py 后必跑)
|
||||||
python build_exe.py # 打包 → ../release/HDMI-Tool.exe(自动装 PyInstaller;
|
python build_exe.py # 打包 → ../release/DLPilot.exe(自动装 PyInstaller;
|
||||||
# 内置 pyserial/customtkinter, CTk 主题数据自动收集)
|
# 内置 pyserial/customtkinter, CTk 主题数据自动收集)
|
||||||
python build_exe.py --debug # 额外出一个带控制台的调试变体(--dump 可见输出)
|
python build_exe.py --debug # 额外出一个带控制台的调试变体(--dump 可见输出)
|
||||||
python package_release.py 0.2.0 # 组装 release/HDMI-Tool-v0.2.0-win64.zip
|
python package_release.py 0.2.0 # 组装 release/DLPilot-v0.2.0-win64.zip
|
||||||
python publish_gitea.py HDMI-Tool-v0.2.0-win64.zip --insecure # 上传 Gitea Release(需 GITEA_TOKEN)
|
python publish_gitea.py DLPilot-v0.2.0-win64.zip --insecure # 上传 Gitea Release(需 GITEA_TOKEN)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 10. 注意事项 / FAQ
|
## 10. 注意事项 / FAQ
|
||||||
@@ -235,6 +235,6 @@ python publish_gitea.py HDMI-Tool-v0.2.0-win64.zip --insecure # 上传 Gitea R
|
|||||||
- **exe 放只读目录会怎样**:自定义图片与 `pattern_slots.json` 写在 exe 旁边,只读目录会导致配置存不下;
|
- **exe 放只读目录会怎样**:自定义图片与 `pattern_slots.json` 写在 exe 旁边,只读目录会导致配置存不下;
|
||||||
- **重新打包后图标没变**:Windows 图标缓存,`ie4uinit -show` 或改个名即可;
|
- **重新打包后图标没变**:Windows 图标缓存,`ie4uinit -show` 或改个名即可;
|
||||||
- **多屏序号**:切分辨率前先确认显示器序号(GUI 下拉框与 `hdmi_source.bat -List` 输出一致);
|
- **多屏序号**:切分辨率前先确认显示器序号(GUI 下拉框与 `hdmi_source.bat -List` 输出一致);
|
||||||
- **残留进程**:修改源码重新打包前先结束残留的 HDMI-Tool 进程(`build_exe.py` 会自动 taskkill);
|
- **残留进程**:修改源码重新打包前先结束残留的 DLPilot 进程(`build_exe.py` 会自动 taskkill);
|
||||||
- **改 logo**:改 `src/logos/logo_ph_orange.svg` → `python src/logos/make_ico.py` → 重新打包;
|
- **改 logo**:改 `src/logos/logo_ph_orange.svg` → `python src/logos/make_ico.py` → 重新打包;
|
||||||
- **配置互不影响**:exe 与源码脚本各自按所在目录保存 `pattern_slots.json`,两份安装互不干扰。
|
- **配置互不影响**:exe 与源码脚本各自按所在目录保存 `pattern_slots.json`,两份安装互不干扰。
|
||||||
|
|||||||
+56
-13
@@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
HDMI-Tool 主界面 — CustomTkinter 双栏仪表盘
|
DLPilot 主界面 — CustomTkinter 双栏仪表盘
|
||||||
================================================================
|
================================================================
|
||||||
布局(HDMI-Tool/UI参考布局.svg):
|
布局(DLPilot/UI参考布局.svg):
|
||||||
左列 显示器选择 | 支持的模式 | EDID 信息 | 测试图案/纯色/自定义 | EDID 原始数据
|
左列 显示器选择 | 支持的模式 | EDID 信息 | 测试图案/纯色/自定义 | EDID 原始数据
|
||||||
右列 串口选择与参数 | 串口数据(收发日志) | 预设与自定义命令 | 光强/定时快捷滑条
|
右列 串口选择与参数 | 串口数据(收发日志) | 预设与自定义命令 | 光强/定时快捷滑条
|
||||||
默认深色外观, 顶栏可切换 Dark/Light/System。
|
默认深色外观, 顶栏可切换 Dark/Light/System。
|
||||||
@@ -12,6 +12,7 @@ HDMI-Tool 主界面 — CustomTkinter 双栏仪表盘
|
|||||||
投屏窗口在 patterns, 串口协议在 dlpc_rs485, 运行配置在 config。
|
投屏窗口在 patterns, 串口协议在 dlpc_rs485, 运行配置在 config。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import ctypes
|
||||||
import ctypes
|
import ctypes
|
||||||
import os
|
import os
|
||||||
import queue
|
import queue
|
||||||
@@ -63,7 +64,11 @@ def run_gui(auto_close=0):
|
|||||||
class App(ctk.CTk):
|
class App(ctk.CTk):
|
||||||
def __init__(self, auto_close=0):
|
def __init__(self, auto_close=0):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.title('HDMI-Tool — EDID 查看器 + 测试图案 + 光机控制 (LT8619C 转接板调试)')
|
self.title('DLPilot — 3D 光固化光机调试台 (EDID · 测试图案 · RS485 光机控制)')
|
||||||
|
try: # 任务栏独立分组
|
||||||
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('hulk.DLPilot')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
self.geometry('1440x920')
|
self.geometry('1440x920')
|
||||||
self.minsize(1180, 800)
|
self.minsize(1180, 800)
|
||||||
ic = get_icon_path()
|
ic = get_icon_path()
|
||||||
@@ -97,8 +102,10 @@ class App(ctk.CTk):
|
|||||||
def _set_appearance(self, mode):
|
def _set_appearance(self, mode):
|
||||||
ctk.set_appearance_mode(mode)
|
ctk.set_appearance_mode(mode)
|
||||||
|
|
||||||
def _card(self, parent, title, button=None, command=None, right_label=None):
|
def _card(self, parent, title, button=None, command=None, right_label=None,
|
||||||
"""卡片容器: 圆角边框 + 标题行(可带右侧小按钮/右对齐标签), 返回 (卡片, 内容 frame)
|
right_widget=None):
|
||||||
|
"""卡片容器: 圆角边框 + 标题行(可带右侧小按钮/右对齐标签/自定义控件),
|
||||||
|
返回 (卡片, 内容 frame)
|
||||||
|
|
||||||
卡片自身用 grid 参与列布局; 卡片内部(head/content/行控件)一律用 pack。
|
卡片自身用 grid 参与列布局; 卡片内部(head/content/行控件)一律用 pack。
|
||||||
"""
|
"""
|
||||||
@@ -107,6 +114,8 @@ class App(ctk.CTk):
|
|||||||
head = ctk.CTkFrame(card, fg_color='transparent')
|
head = ctk.CTkFrame(card, fg_color='transparent')
|
||||||
head.pack(fill='x', padx=12, pady=(8, 0))
|
head.pack(fill='x', padx=12, pady=(8, 0))
|
||||||
ctk.CTkLabel(head, text=title, font=BOLD, anchor='w').pack(side='left')
|
ctk.CTkLabel(head, text=title, font=BOLD, anchor='w').pack(side='left')
|
||||||
|
if right_widget is not None: # 自定义控件(如 电流读数+查电流)
|
||||||
|
right_widget.pack(side='right')
|
||||||
if right_label is not None:
|
if right_label is not None:
|
||||||
ctk.CTkLabel(head, textvariable=right_label,
|
ctk.CTkLabel(head, textvariable=right_label,
|
||||||
text_color='gray60').pack(side='right')
|
text_color='gray60').pack(side='right')
|
||||||
@@ -120,7 +129,7 @@ class App(ctk.CTk):
|
|||||||
def _build(self):
|
def _build(self):
|
||||||
top = ctk.CTkFrame(self, fg_color='transparent')
|
top = ctk.CTkFrame(self, fg_color='transparent')
|
||||||
top.pack(fill='x', padx=12, pady=(10, 2))
|
top.pack(fill='x', padx=12, pady=(10, 2))
|
||||||
ctk.CTkLabel(top, text='HDMI-Tool', font=TITLE_FONT).pack(side='left')
|
ctk.CTkLabel(top, text='DLPilot', font=TITLE_FONT).pack(side='left')
|
||||||
ctk.CTkLabel(top, text='EDID · 测试图案 · 光机控制',
|
ctk.CTkLabel(top, text='EDID · 测试图案 · 光机控制',
|
||||||
text_color='gray60').pack(side='left', padx=10, pady=(6, 0))
|
text_color='gray60').pack(side='left', padx=10, pady=(6, 0))
|
||||||
seg = ctk.CTkSegmentedButton(top, values=['Dark', 'Light', 'System'],
|
seg = ctk.CTkSegmentedButton(top, values=['Dark', 'Light', 'System'],
|
||||||
@@ -149,8 +158,8 @@ class App(ctk.CTk):
|
|||||||
).pack(expand=True)
|
).pack(expand=True)
|
||||||
|
|
||||||
def _build_left(self, col):
|
def _build_left(self, col):
|
||||||
col.grid_rowconfigure(1, weight=2) # 支持的模式(与 EDID 信息等高)
|
col.grid_rowconfigure(1, weight=2) # 支持的模式
|
||||||
col.grid_rowconfigure(2, weight=2) # EDID 信息
|
col.grid_rowconfigure(2, weight=1) # EDID 信息(压缩高度)
|
||||||
col.grid_rowconfigure(4, weight=0) # EDID 原始数据(固定高, 压缩)
|
col.grid_rowconfigure(4, weight=0) # EDID 原始数据(固定高, 压缩)
|
||||||
col.grid_columnconfigure(0, weight=1)
|
col.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
@@ -218,7 +227,7 @@ class App(ctk.CTk):
|
|||||||
row3 = ctk.CTkFrame(c, fg_color='transparent')
|
row3 = ctk.CTkFrame(c, fg_color='transparent')
|
||||||
row3.pack(fill='x', pady=(6, 0))
|
row3.pack(fill='x', pady=(6, 0))
|
||||||
self.slot_buttons = []
|
self.slot_buttons = []
|
||||||
for i in range(config.SLOT_COUNT):
|
for i in range(3): # 自定义栏位(沿用原 3 槽配置)
|
||||||
cell = ctk.CTkFrame(row3, fg_color='transparent')
|
cell = ctk.CTkFrame(row3, fg_color='transparent')
|
||||||
cell.pack(side='left', padx=(0, 10))
|
cell.pack(side='left', padx=(0, 10))
|
||||||
btn = ctk.CTkButton(cell, text=self.slots[i]['name'], width=96,
|
btn = ctk.CTkButton(cell, text=self.slots[i]['name'], width=96,
|
||||||
@@ -231,6 +240,22 @@ class App(ctk.CTk):
|
|||||||
self.slot_buttons.append(btn)
|
self.slot_buttons.append(btn)
|
||||||
ctk.CTkLabel(row3, text='点击投图, 齿轮按钮配置图片',
|
ctk.CTkLabel(row3, text='点击投图, 齿轮按钮配置图片',
|
||||||
text_color='gray50').pack(side='left', padx=4)
|
text_color='gray50').pack(side='left', padx=4)
|
||||||
|
# -- 光校图案(预留 5 槽): 3D 光固化打印测试/校准用图 --
|
||||||
|
row4 = ctk.CTkFrame(c, fg_color='transparent')
|
||||||
|
row4.pack(fill='x', pady=(6, 0))
|
||||||
|
for i in range(3, config.SLOT_COUNT):
|
||||||
|
cell = ctk.CTkFrame(row4, fg_color='transparent')
|
||||||
|
cell.pack(side='left', padx=(0, 10))
|
||||||
|
btn = ctk.CTkButton(cell, text=self.slots[i]['name'], width=96,
|
||||||
|
command=lambda i=i: self._show_custom(i))
|
||||||
|
btn.pack(side='left')
|
||||||
|
ctk.CTkButton(cell, text='\uE713', width=30, height=24,
|
||||||
|
font=('Segoe MDL2 Assets', 13),
|
||||||
|
command=lambda i=i: self._configure_slot(i)
|
||||||
|
).pack(side='left', padx=(4, 0))
|
||||||
|
self.slot_buttons.append(btn)
|
||||||
|
ctk.CTkLabel(row4, text='校准图案(预留 5 槽, 齿轮改图)',
|
||||||
|
text_color='gray50').pack(side='left', padx=4)
|
||||||
|
|
||||||
# -- EDID 原始数据 --
|
# -- EDID 原始数据 --
|
||||||
card, c = self._card(col, 'EDID 原始数据',
|
card, c = self._card(col, 'EDID 原始数据',
|
||||||
@@ -293,12 +318,20 @@ class App(ctk.CTk):
|
|||||||
'累加和校验; 全部命令见 README"光机控制"')
|
'累加和校验; 全部命令见 README"光机控制"')
|
||||||
|
|
||||||
# -- 光机命令 --
|
# -- 光机命令 --
|
||||||
card, c = self._card(col,'光机命令 — 预设 / 自定义 / TEC')
|
# 标题行右侧: 电流实时读数 + 查电流按钮(okR..G..B.. 应答解析)
|
||||||
|
cur_frame = ctk.CTkFrame(self, fg_color='transparent')
|
||||||
|
self.var_current = tk.StringVar(value='电流: —')
|
||||||
|
ctk.CTkLabel(cur_frame, textvariable=self.var_current, width=168,
|
||||||
|
anchor='e', text_color='#3B8ED0').pack(side='left')
|
||||||
|
ctk.CTkButton(cur_frame, text='查电流', width=64, height=24,
|
||||||
|
command=self._query_current).pack(side='left', padx=(6, 0))
|
||||||
|
card, c = self._card(col,'光机命令 — 预设 / 自定义 / TEC',
|
||||||
|
right_widget=cur_frame)
|
||||||
card.grid(row=2, column=0, sticky='ew', pady=(10, 0))
|
card.grid(row=2, column=0, sticky='ew', pady=(10, 0))
|
||||||
row1 = ctk.CTkFrame(c, fg_color='transparent')
|
row1 = ctk.CTkFrame(c, fg_color='transparent')
|
||||||
row1.pack(fill='x')
|
row1.pack(fill='x')
|
||||||
for name, cmd in (('开光机', 'M730S0'), ('关光机', 'M730S1'),
|
for name, cmd in (('开光机', 'M730S0'), ('关光机', 'M730S1'),
|
||||||
('查电流', 'M732'), ('查版本', 'M999'), ('软件重启', 'M888'),
|
('查版本', 'M999'), ('软件重启', 'M888'),
|
||||||
('开TEC', 'M7S0'), ('关TEC', 'M7S1'), ('TEC33.0°C', 'M8S330')):
|
('开TEC', 'M7S0'), ('关TEC', 'M7S1'), ('TEC33.0°C', 'M8S330')):
|
||||||
ctk.CTkButton(row1, text=name, width=64,
|
ctk.CTkButton(row1, text=name, width=64,
|
||||||
command=lambda cc=cmd: self._dlpc_send(cc)
|
command=lambda cc=cmd: self._dlpc_send(cc)
|
||||||
@@ -365,7 +398,7 @@ class App(ctk.CTk):
|
|||||||
textvariable=self.var_light)
|
textvariable=self.var_light)
|
||||||
self.ent_light.pack(side='left')
|
self.ent_light.pack(side='left')
|
||||||
self.ent_light.bind('<Return>', self._light_entry_apply)
|
self.ent_light.bind('<Return>', self._light_entry_apply)
|
||||||
ctk.CTkButton(rowa, text='下发 M731S', width=110,
|
ctk.CTkButton(rowa, text='下发电流值', width=110,
|
||||||
command=self._dlpc_send_light).pack(side='left', padx=(6, 0))
|
command=self._dlpc_send_light).pack(side='left', padx=(6, 0))
|
||||||
rowb = ctk.CTkFrame(c, fg_color='transparent')
|
rowb = ctk.CTkFrame(c, fg_color='transparent')
|
||||||
rowb.pack(fill='x', pady=(8, 0))
|
rowb.pack(fill='x', pady=(8, 0))
|
||||||
@@ -395,7 +428,7 @@ class App(ctk.CTk):
|
|||||||
textvariable=self.var_tec)
|
textvariable=self.var_tec)
|
||||||
self.ent_tec.pack(side='left')
|
self.ent_tec.pack(side='left')
|
||||||
self.ent_tec.bind('<Return>', self._tec_entry_apply)
|
self.ent_tec.bind('<Return>', self._tec_entry_apply)
|
||||||
ctk.CTkButton(rowc, text='下发 M8S', width=110,
|
ctk.CTkButton(rowc, text='下发温度值', width=110,
|
||||||
command=self._dlpc_send_tec).pack(side='left', padx=(6, 0))
|
command=self._dlpc_send_tec).pack(side='left', padx=(6, 0))
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -634,8 +667,16 @@ class App(ctk.CTk):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
text = f'{which}: {m.group(1)}'
|
text = f'{which}: {m.group(1)}'
|
||||||
self._dlpc_log_q.put(('temp', text))
|
self._dlpc_log_q.put(('temp', text))
|
||||||
|
# 电流查询应答: okR<n>G<n>B<n> -> 标题行实时读数
|
||||||
|
m = re.search(r'← okR(\d+)G(\d+)B(\d+)', line)
|
||||||
|
if m:
|
||||||
|
self._dlpc_log_q.put(('current', f'电流 R:{m.group(1)} '
|
||||||
|
f'G:{m.group(2)} B:{m.group(3)}'))
|
||||||
self._dlpc_log_q.put(('event', line))
|
self._dlpc_log_q.put(('event', line))
|
||||||
|
|
||||||
|
def _query_current(self):
|
||||||
|
self._dlpc_send('M732')
|
||||||
|
|
||||||
def _query_dmd(self):
|
def _query_dmd(self):
|
||||||
self._tl_order.append('DMD')
|
self._tl_order.append('DMD')
|
||||||
self._dlpc_send('M201')
|
self._dlpc_send('M201')
|
||||||
@@ -666,6 +707,8 @@ class App(ctk.CTk):
|
|||||||
self.var_dmd.set(text)
|
self.var_dmd.set(text)
|
||||||
else:
|
else:
|
||||||
self.var_lamp.set(text)
|
self.var_lamp.set(text)
|
||||||
|
elif kind == 'current':
|
||||||
|
self.var_current.set(text)
|
||||||
self._dlpc_log(text)
|
self._dlpc_log(text)
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
把 hdmi_gui.py 打包成单文件 exe(工具名: HDMI-Tool)
|
把 hdmi_gui.py 打包成单文件 exe(工具名: DLPilot)
|
||||||
================================
|
================================
|
||||||
使用 PyInstaller --onefile --noconsole: Python 解释器 + 标准库 + tkinter
|
使用 PyInstaller --onefile --noconsole: Python 解释器 + 标准库 + tkinter
|
||||||
全部打进一个 exe, 目标机器无需安装任何依赖。
|
全部打进一个 exe, 目标机器无需安装任何依赖。
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
python build_exe.py 自动安装 PyInstaller(如缺)并打包
|
python build_exe.py 自动安装 PyInstaller(如缺)并打包
|
||||||
python build_exe.py --debug 额外打一个带控制台的变体(--dump 可用)
|
python build_exe.py --debug 额外打一个带控制台的变体(--dump 可用)
|
||||||
|
|
||||||
产物: release/HDMI-Tool.exe(及 --debug 时的 HDMI-Tool-console.exe)
|
产物: release/DLPilot.exe(及 --debug 时的 DLPilot-console.exe)
|
||||||
首次运行 onefile exe 会先解压到临时目录, 启动比脚本慢一两秒, 属正常现象。
|
首次运行 onefile exe 会先解压到临时目录, 启动比脚本慢一两秒, 属正常现象。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -84,10 +84,10 @@ def main():
|
|||||||
build_console = '--debug' in sys.argv
|
build_console = '--debug' in sys.argv
|
||||||
ensure_pyinstaller()
|
ensure_pyinstaller()
|
||||||
# 常规版: 双击即用, 无黑框(GUI/图案/自定义栏位全部可用, --dump 除外)
|
# 常规版: 双击即用, 无黑框(GUI/图案/自定义栏位全部可用, --dump 除外)
|
||||||
build('HDMI-Tool', ['--noconsole'])
|
build('DLPilot', ['--noconsole'])
|
||||||
if build_console:
|
if build_console:
|
||||||
# 调试版: 带控制台, --dump / 异常栈可见
|
# 调试版: 带控制台, --dump / 异常栈可见
|
||||||
build('HDMI-Tool-console', [])
|
build('DLPilot-console', [])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ if getattr(sys, 'frozen', False):
|
|||||||
BASE_DIR = os.path.dirname(os.path.abspath(sys.executable))
|
BASE_DIR = os.path.dirname(os.path.abspath(sys.executable))
|
||||||
else:
|
else:
|
||||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
SLOT_COUNT = 3
|
SLOT_COUNT = 8
|
||||||
SLOT_CONFIG = os.path.join(BASE_DIR, 'pattern_slots.json')
|
SLOT_CONFIG = os.path.join(BASE_DIR, 'pattern_slots.json')
|
||||||
IMG_EXTS = ['.png', '.gif'] + (['.jpg', '.jpeg', '.bmp', '.webp'] if HAS_PIL else [])
|
IMG_EXTS = ['.png', '.gif'] + (['.jpg', '.jpeg', '.bmp', '.webp'] if HAS_PIL else [])
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
组装 HDMI-Tool 发布包: exe + 附属资产 → 一个文件夹 + 一个 zip(解压即用)
|
组装 DLPilot 发布包: exe + 附属资产 → 一个文件夹 + 一个 zip(解压即用)
|
||||||
================================================================
|
================================================================
|
||||||
先把 assets/ 的图案复制进 release/(与 exe 平铺), 使 release/ 本身就是
|
先把 assets/ 的图案复制进 release/(与 exe 平铺), 使 release/ 本身就是
|
||||||
可直接使用的完整文件夹; 再原样压成 zip —— 两者内容始终一致。
|
可直接使用的完整文件夹; 再原样压成 zip —— 两者内容始终一致。
|
||||||
|
|
||||||
zip 解压后根目录为 HDMI-Tool/, 与 exe 运行目录结构一致:
|
zip 解压后根目录为 DLPilot/, 与 exe 运行目录结构一致:
|
||||||
HDMI-Tool.exe 主程序(先运行 build_exe.py 打包)
|
DLPilot.exe 主程序(先运行 build_exe.py 打包)
|
||||||
pattern_slots.json 预置自定义栏位(指向前 3 张 bw 图案)
|
pattern_slots.json 预置自定义栏位(指向前 3 张 bw 图案)
|
||||||
bw_*.png 640x360 黑白测试图 ×5(自定义栏位用)
|
bw_*.png 640x360 黑白测试图 ×5(自定义栏位用)
|
||||||
solid_*.png 800x600 纯色测试图 ×10(RGB 位交换测试用)
|
solid_*.png 800x600 纯色测试图 ×10(RGB 位交换测试用)
|
||||||
README.md 使用说明
|
README.md 使用说明
|
||||||
|
|
||||||
用法:
|
用法:
|
||||||
python package_release.py 版本号自动取最近 git tag(HDMI-Tool-v*)
|
python package_release.py 版本号自动取最近 git tag(DLPilot-v*)
|
||||||
python package_release.py 0.1.0 手动指定版本号
|
python package_release.py 0.1.0 手动指定版本号
|
||||||
产物: release/HDMI-Tool-v<版本>-win64.zip(zip 不入库, 上传到 Gitea Release)
|
产物: release/DLPilot-v<版本>-win64.zip(zip 不入库, 上传到 Gitea Release)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -35,23 +35,23 @@ PATTERN_GLOBS = ('bw_*.png', 'solid_*.png')
|
|||||||
|
|
||||||
|
|
||||||
def detect_version():
|
def detect_version():
|
||||||
"""从最近的 HDMI-Tool-v* tag 推断版本号, 无 tag 则报错提示手动指定"""
|
"""从最近的 DLPilot-v* tag 推断版本号, 无 tag 则报错提示手动指定"""
|
||||||
try:
|
try:
|
||||||
out = subprocess.check_output(
|
out = subprocess.check_output(
|
||||||
['git', 'describe', '--tags', '--abbrev=0', '--match', 'HDMI-Tool-v*'],
|
['git', 'describe', '--tags', '--abbrev=0', '--match', 'DLPilot-v*'],
|
||||||
cwd=BASE, stderr=subprocess.DEVNULL)
|
cwd=BASE, stderr=subprocess.DEVNULL)
|
||||||
return out.decode().strip().removeprefix('HDMI-Tool-v')
|
return out.decode().strip().removeprefix('DLPilot-v')
|
||||||
except Exception:
|
except Exception:
|
||||||
sys.exit('未能从 git tag 推断版本号, 请手动指定: python package_release.py <版本号>')
|
sys.exit('未能从 git tag 推断版本号, 请手动指定: python package_release.py <版本号>')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
version = (sys.argv[1] if len(sys.argv) > 1 else detect_version()).lstrip('v')
|
version = (sys.argv[1] if len(sys.argv) > 1 else detect_version()).lstrip('v')
|
||||||
exe = os.path.join(RELEASE, 'HDMI-Tool.exe')
|
exe = os.path.join(RELEASE, 'DLPilot.exe')
|
||||||
slots = os.path.join(RELEASE, 'pattern_slots.json')
|
slots = os.path.join(RELEASE, 'pattern_slots.json')
|
||||||
readme = os.path.join(BASE, 'README.md')
|
readme = os.path.join(BASE, 'README.md')
|
||||||
if not os.path.exists(exe):
|
if not os.path.exists(exe):
|
||||||
sys.exit('缺少 release/HDMI-Tool.exe, 先运行: python build_exe.py')
|
sys.exit('缺少 release/DLPilot.exe, 先运行: python build_exe.py')
|
||||||
for must in (slots, readme):
|
for must in (slots, readme):
|
||||||
if not os.path.exists(must):
|
if not os.path.exists(must):
|
||||||
sys.exit(f'缺少 {must}')
|
sys.exit(f'缺少 {must}')
|
||||||
@@ -70,11 +70,11 @@ def main():
|
|||||||
shutil.copy2(os.path.join(ASSETS, p), os.path.join(RELEASE, p))
|
shutil.copy2(os.path.join(ASSETS, p), os.path.join(RELEASE, p))
|
||||||
shutil.copy2(readme, os.path.join(RELEASE, 'README.md'))
|
shutil.copy2(readme, os.path.join(RELEASE, 'README.md'))
|
||||||
|
|
||||||
zip_name = f'HDMI-Tool-v{version}-win64.zip'
|
zip_name = f'DLPilot-v{version}-win64.zip'
|
||||||
zip_path = os.path.join(RELEASE, zip_name)
|
zip_path = os.path.join(RELEASE, zip_name)
|
||||||
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as z:
|
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as z:
|
||||||
for p in ['HDMI-Tool.exe', 'pattern_slots.json', 'README.md'] + patterns:
|
for p in ['DLPilot.exe', 'pattern_slots.json', 'README.md'] + patterns:
|
||||||
z.write(os.path.join(RELEASE, p), f'HDMI-Tool/{p}')
|
z.write(os.path.join(RELEASE, p), f'DLPilot/{p}')
|
||||||
print(f'发布文件夹: {RELEASE} (exe+配置+说明+{len(patterns)} 张图案, 平铺即用)')
|
print(f'发布文件夹: {RELEASE} (exe+配置+说明+{len(patterns)} 张图案, 平铺即用)')
|
||||||
print(f'发布包: {zip_path} ({os.path.getsize(zip_path) / 1024 / 1024:.1f} MB)')
|
print(f'发布包: {zip_path} ({os.path.getsize(zip_path) / 1024 / 1024:.1f} MB)')
|
||||||
print('下一步上传: python publish_gitea.py', zip_name)
|
print('下一步上传: python publish_gitea.py', zip_name)
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
创建/更新 Gitea Release 并上传发布 zip(纯标准库, 无需安装依赖)
|
创建/更新 Gitea Release 并上传发布 zip(纯标准库, 无需安装依赖)
|
||||||
================================================================
|
================================================================
|
||||||
用法:
|
用法:
|
||||||
python publish_gitea.py HDMI-Tool-v0.1.0-win64.zip
|
python publish_gitea.py DLPilot-v0.1.0-win64.zip
|
||||||
python publish_gitea.py <zip> --notes-file release/notes-v0.1.0.md
|
python publish_gitea.py <zip> --notes-file release/notes-v0.1.0.md
|
||||||
python publish_gitea.py <zip> --tag HDMI-Tool-v0.1.0 --replace
|
python publish_gitea.py <zip> --tag DLPilot-v0.1.0 --replace
|
||||||
|
|
||||||
行为:
|
行为:
|
||||||
- tag 与版本默认取 zip 文件名(HDMI-Tool-vX.Y.Z-win64.zip → HDMI-Tool-vX.Y.Z)
|
- tag 与版本默认取 zip 文件名(DLPilot-vX.Y.Z-win64.zip → DLPilot-vX.Y.Z)
|
||||||
- release 不存在则创建(tag 不存在时 Gitea 在默认分支头自动建 tag);
|
- release 不存在则创建(tag 不存在时 Gitea 在默认分支头自动建 tag);
|
||||||
已存在则复用, 仅上传/更新资产
|
已存在则复用, 仅上传/更新资产
|
||||||
- release 上已有同名资产时: 默认跳过, --replace 删旧再传
|
- release 上已有同名资产时: 默认跳过, --replace 删旧再传
|
||||||
@@ -27,16 +27,16 @@ import urllib.error
|
|||||||
import urllib.request
|
import urllib.request
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
DEFAULT_NOTES = """## HDMI-Tool {version}
|
DEFAULT_NOTES = """## DLPilot {version}
|
||||||
|
|
||||||
HDMI 源端调试工具(LT8619C → DLPC3421 转接板配套): EDID 查看/逐字节解析、
|
HDMI 源端调试工具(LT8619C → DLPC3421 转接板配套): EDID 查看/逐字节解析、
|
||||||
分辨率切换、纯色与测试图案全屏投屏。
|
分辨率切换、纯色与测试图案全屏投屏。
|
||||||
|
|
||||||
### 安装
|
### 安装
|
||||||
下载 `HDMI-Tool-v{version}-win64.zip`, 解压后双击 `HDMI-Tool.exe`(Windows 10/11 x64, 免安装)。
|
下载 `DLPilot-v{version}-win64.zip`, 解压后双击 `DLPilot.exe`(Windows 10/11 x64, 免安装)。
|
||||||
|
|
||||||
### 包内容
|
### 包内容
|
||||||
- `HDMI-Tool.exe` — 主程序
|
- `DLPilot.exe` — 主程序
|
||||||
- `pattern_slots.json` — 预置自定义栏位(指向 bw_*.png)
|
- `pattern_slots.json` — 预置自定义栏位(指向 bw_*.png)
|
||||||
- `bw_*.png` ×5 / `solid_*.png` ×10 — 测试图案
|
- `bw_*.png` ×5 / `solid_*.png` ×10 — 测试图案
|
||||||
- `README.md` — 完整使用说明
|
- `README.md` — 完整使用说明
|
||||||
@@ -119,7 +119,7 @@ def main():
|
|||||||
sys.exit('缺少 API token: 传 --token 或设环境变量 GITEA_TOKEN')
|
sys.exit('缺少 API token: 传 --token 或设环境变量 GITEA_TOKEN')
|
||||||
|
|
||||||
tag = args.tag or re.sub(r'-win64\.zip$', '', os.path.basename(args.zipfile_path))
|
tag = args.tag or re.sub(r'-win64\.zip$', '', os.path.basename(args.zipfile_path))
|
||||||
version = tag.removeprefix('HDMI-Tool-v')
|
version = tag.removeprefix('DLPilot-v')
|
||||||
notes = open(args.notes_file, encoding='utf-8').read() if args.notes_file \
|
notes = open(args.notes_file, encoding='utf-8').read() if args.notes_file \
|
||||||
else DEFAULT_NOTES.format(version=version)
|
else DEFAULT_NOTES.format(version=version)
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ def main():
|
|||||||
else:
|
else:
|
||||||
status, rel = api.request('POST', '/releases', json.dumps({
|
status, rel = api.request('POST', '/releases', json.dumps({
|
||||||
'tag_name': tag,
|
'tag_name': tag,
|
||||||
'name': f'HDMI-Tool v{version}',
|
'name': f'DLPilot v{version}',
|
||||||
'body': notes,
|
'body': notes,
|
||||||
}).encode(), {'Content-Type': 'application/json'})
|
}).encode(), {'Content-Type': 'application/json'})
|
||||||
if status != 201:
|
if status != 201:
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板调试配套上位机工
|
|||||||
|
|
||||||
| 工具 | 用途 | 获取 |
|
| 工具 | 用途 | 获取 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| [HDMI-Tool](HDMI-Tool/) | HDMI 源端(EDID 查看/逐字节解析、分辨率切换、纯色与测试图案全屏投屏)+ 光机控制(RS485→GD32 网关→DLPC3421:开关光机/设光强/查温度电流) | 到 [Releases](https://gitea.hulk.wang/hulk/LT8619C_Debug_Tools/releases) 下 `HDMI-Tool-vX.Y.Z-win64.zip`,解压即用;详见 [HDMI-Tool/README.md](HDMI-Tool/README.md) |
|
| [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) |
|
||||||
| [I2C-Inject](I2C-Inject/) | LT8619C 寄存器在线读写:RP2040 注入器在 demo 板 I2C 总线上择机注入(避让主控轮询,写后自动读回校验) | 需配合 RP2040 固件 `rp2040_inject.py`;详见 [I2C-Inject/README.md](I2C-Inject/README.md) |
|
| [I2C-Inject](I2C-Inject/) | LT8619C 寄存器在线读写:RP2040 注入器在 demo 板 I2C 总线上择机注入(避让主控轮询,写后自动读回校验) | 需配合 RP2040 固件 `rp2040_inject.py`;详见 [I2C-Inject/README.md](I2C-Inject/README.md) |
|
||||||
|
|
||||||
## 环境要求
|
## 环境要求
|
||||||
|
|
||||||
- 发布版 zip 开箱即用(Windows 10/11 x64,无需安装 Python)
|
- 发布版 zip 开箱即用(Windows 10/11 x64,无需安装 Python)
|
||||||
- 源码运行:Python ≥3.10;HDMI-Tool 命令行/EDID 纯标准库,GUI 需
|
- 源码运行:Python ≥3.10;DLPilot 命令行/EDID 纯标准库,GUI 需
|
||||||
`py -m pip install customtkinter`(自定义图片 JPG/BMP 可选 Pillow、光机控制可选 pyserial);
|
`py -m pip install customtkinter`(自定义图片 JPG/BMP 可选 Pillow、光机控制可选 pyserial);
|
||||||
I2C-Inject 需 `py -m pip install pyserial`
|
I2C-Inject 需 `py -m pip install pyserial`
|
||||||
- 重新打包:`HDMI-Tool/src/build_exe.py`(自动安装 PyInstaller);I2C-Inject 目录内 `python build_exe.py`
|
- 重新打包:`DLPilot/src/build_exe.py`(自动安装 PyInstaller);I2C-Inject 目录内 `python build_exe.py`
|
||||||
|
|
||||||
## 目录结构
|
## 目录结构
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板调试配套上位机工
|
|||||||
|
|
||||||
```
|
```
|
||||||
LT8619C_Debug_Tools/
|
LT8619C_Debug_Tools/
|
||||||
├── HDMI-Tool/
|
├── DLPilot/
|
||||||
│ ├── src/ # 源码 + 打包/发布脚本 + 图标源
|
│ ├── src/ # 源码 + 打包/发布脚本 + 图标源
|
||||||
│ ├── assets/ # 生成的测试图案 PNG(gen_*.py 产物)
|
│ ├── assets/ # 生成的测试图案 PNG(gen_*.py 产物)
|
||||||
│ ├── release/ # 打包 exe + 运行配置(入库);发布 zip(不入库)
|
│ ├── release/ # 打包 exe + 运行配置(入库);发布 zip(不入库)
|
||||||
@@ -36,13 +36,13 @@ LT8619C_Debug_Tools/
|
|||||||
└── README.md
|
└── README.md
|
||||||
```
|
```
|
||||||
|
|
||||||
## 发布流程(HDMI-Tool)
|
## 发布流程(DLPilot)
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
cd HDMI-Tool/src
|
cd DLPilot/src
|
||||||
python build_exe.py # 打包 → ../release/HDMI-Tool.exe
|
python build_exe.py # 打包 → ../release/DLPilot.exe
|
||||||
python package_release.py <版本> # → ../release/HDMI-Tool-v<版本>-win64.zip
|
python package_release.py <版本> # → ../release/DLPilot-v<版本>-win64.zip
|
||||||
python publish_gitea.py HDMI-Tool-v<版本>-win64.zip --insecure # 上传 Gitea Release(需 GITEA_TOKEN)
|
python publish_gitea.py DLPilot-v<版本>-win64.zip --insecure # 上传 Gitea Release(需 GITEA_TOKEN)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 备注
|
## 备注
|
||||||
|
|||||||
Reference in New Issue
Block a user