Files
MAG160C/analysis/history/交接_完整逆向工程说明_20260811.md

891 lines
35 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MAG160C 热像仪逆向工程完整交接说明
## 1. 文档目的
本文档用于把 `C:\Project\MAG160C` 整个工程移交给另一位工程师或另一位 AI。目标不是只说明当前代码怎么编译,而是把以下内容全部交代清楚:
- 工程每个主要目录的用途。
- MAG160C 硬件、USB、帧格式和驱动环境。
- 官方 Windows、Android、Linux SDK 的逆向成果。
- 官方 CoreSDKLib.dll 实际渲染主链路。
- `mag160c_demo3.c` 当前实现和所有实验性分支。
- 已经解决的问题、仍未解决的问题和曾经失败的路线。
- 如何安装工具、构建程序、连接设备、抓帧、运行和诊断。
- 如何继续逆向低温残影,并避免重复走已经验证失败的路线。
- 让下一位 AI 从零开始接手时可以直接使用的中文提示词。
文档日期:2026-08-11。工作目录:`C:\Project\MAG160C`。远端仓库:`https://git.zxcli.top/zxc/MAG160C.git`
## 2. 一分钟结论
### 2.1 硬件
- 设备是 MAG160C 160×120 红外热像仪。
- USB 设备常见身份是 VID `0x833C`、PID `0x0001`
- 它不是普通 UVC 热像仪,而是厂商自定义 USB bulk 协议。
- 命令使用 EP `0x03`,响应使用 EP `0x82`,实时帧使用 EP `0x81`
- 原始实时帧包含 160×120 个小端 `uint16` 像素。
### 2.2 官方渲染链路
官方 Windows `CoreSDKLib.dll` 的主链路已经被活体抓帧和反汇编共同确认:
```text
USB type=0 原始帧
-> f20 平滑器 0x41f10,当前 mode=1,基本是逐帧 memcpy
-> NUC 0x180017200
d2 = (f20[i] - ref[i]) >> 1
每像素两个 signed threshold 选择三个 segment
每像素 gain/off 查表
out = off + ((gain * d2) >> 12)
clamp 到 [0, 65535]
-> 0x180017330,固定表驱动的坏点/盲元邻域补偿
-> 可选 0x18001e920 temporal filter;当前实测 mode=1,通常跳过
-> 窗口 hi/lo
-> 1024 项灰度 LUT
-> 256 项 BGR 调色板
-> 320×240 输出
```
### 2.3 官方参考帧
- 官方参考缓冲来自 `dev+0x41ef0`,对象起点是 `dev+0x41ee0`
- 参考平滑器是 mode=4,启动阶段通过累计平均形成参考。
- 正常 type=0 帧不会逐帧重新采集整幅参考。
- FFC 后空间结构通常保持,只做全局基线变化或重新进入内部配置过程。
- 官方参考不是 demo3 当前的“每帧根据场景自适应参考”。
### 2.4 当前 demo3 状态
当前 demo3 已经接入一组从官方活体抓取并验证过的三段逐像素 NUC 表:
- `build-artifacts/mag160c_official_nuc_gain.bin`
- `build-artifacts/mag160c_official_nuc_thr.bin`
当前默认策略是:
- `CONSTANT_REF=1`
- `BADMAP_ENABLE=0`
- 官方表存在时使用三段逐像素 gain/off/threshold 查表。
- 使用当前场景中值在官方 NUC 输出域反求一个全局参考偏置,使中值约为 `NUC_CENTER=9804`
- `SBNUC_ENABLE=1`,但实际只允许“曾经进入热态、后来变成持续负残差”的像素在运动结束后自愈。
- 正残差不会写入参考,避免热目标被吸收。
- 显示层 `deghost_nuc()` 不调用。
当前仍未完全解决:
- 低温区域静止时间较长后仍可能出现残影。
- 某些固定参考失配会表现为黑洞。
- 官方每次 FFC/传感器温度区间变化后会重新生成 NUC 表;demo3 当前使用一组静态抓取表,没有完整复刻官方温度端点插值和运行时重建。
- 官方 `0x180017330` 的固定盲元补偿记录还没有完整接入 demo3 的新 NUC 表路径。
- 因此当前版本是比线性近似更接近官方的研究基线,不应宣称已经完全复刻官方。
## 3. 目录说明
### 3.1 根目录
| 路径 | 用途 |
|---|---|
| `README.md` | 仓库入口和最短说明。 |
| `交接_完整逆向工程说明_20260811.md` | 本完整交接文档。 |
| `findings.md` | 早期和中期的综合逆向发现,包含 Windows、Android、Linux SDK 证据。 |
| `progress.md` | 按日期记录的长期工程进度、协议恢复和工具安装记录。 |
| `task_plan.md` | 早期 Linux SDK 实现计划和历史任务状态。后续热像渲染工作应以本交接文档和 `analysis/handoff_*.md` 为准。 |
| `frame_stats.txt` | 历史原始帧统计。 |
| `pair_*.win``pair_*.win2``pair_*.nuctab` | 根目录中遗留的官方抓帧窗口、字段和短 NUC 表样本。完整抓帧在 `analysis/pairs_*`。 |
| `.gitattributes` | Git LFS 大文件规则。 |
| `.tools/` | 逆向分析工具、Python 包和下载缓存。 |
| `.agents/` | 当前为空,保留目录结构。 |
| `.superpowers/` | 早期计划工具的资料,当前不参与 demo3 运行。 |
| `app/` | 原厂 APK 和 PC 分析程序。 |
| `IR_Camera_SDK-1.0.1/` | 原厂 Windows、Android、Linux SDK、示例、驱动、DLL、SO 和文档。 |
| `vendor-docs/` | 从根目录整理出的模块硬件文档。 |
### 3.2 `csdk/`
这是当前维护的纯 C SDK 和 Windows 工具目录。
| 路径 | 用途 |
|---|---|
| `csdk/include/` | 对外头文件和 C API。 |
| `csdk/src/mag160c_frame.c` | `0x1bb1b11b` / `0x1bb1b11c` 帧解析和流组装。 |
| `csdk/src/mag160c_ir.c` | libusb 设备打开、命令、启动、停止、FFC、帧线程。 |
| `csdk/src/mag160c_temp.c` | 原始响应、PWL 校正、T2E 温度换算。 |
| `csdk/src/mag160c_tcm.c` | TCM 的 `0x7e` 帧和校验。 |
| `csdk/src/mag160c_display.c` | 坏点、显示、FFC 调度、线性温度工具。 |
| `csdk/src/mag160c_tables.h` | 从官方二进制提取的温度表。 |
| `csdk/tools/mag160c_demo3.c` | 当前主要 Windows 直连、渲染和残影实验程序。 |
| `csdk/tools/mag160c_demo2.c` | 历史显示管线和 MOG/NUC 实验版本。 |
| `csdk/tools/tsdk_pair2.c` | 官方 ThermalSDK 活体同帧抓帧工具。已修正 gain/thr 文件覆盖问题。 |
| `csdk/tests/` | C SDK 纯计算、协议、温度和显示测试。 |
| `csdk/third_party/libusb/win64/` | Windows x64 libusb 头文件、DLL 和 MinGW 导入库。 |
| `csdk/CMakeLists.txt` | CMake 构建文件。当前环境没有 CMake,主要使用直接 GCC 命令。 |
| `csdk/WINDOWS_TESTING.md` | USBPcap、Wireshark、MinGW 和硬件测试指南。 |
### 3.3 `analysis/`
这是逆向工程的核心证据目录。
| 路径 | 用途 |
|---|---|
| `analysis/disasm/` | Windows CoreSDK、Linux libmagcore、Android ARM64 的反汇编、符号和函数切片。 |
| `analysis/protocol_spec.md` | USB 协议、帧格式、命令、温度和 NUC 公式的正式规格。 |
| `analysis/progress_reverse.md` | 官方渲染主链和反汇编阶段性结论。 |
| `analysis/handoff_20260810.md` | demo2 早期路线、MOG、平场和问题演化。 |
| `analysis/handoff_20260811.md` | 较短的 2026-08-11 交接。 |
| `analysis/handoff_20260811_full.md` | 当前残影问题最重要的交接文档之一。 |
| `analysis/handoff_20260812.md` | 官方活体抓帧、NUC 和显示数据分析。 |
| `analysis/handoff_20260812_night.md` | 平滑器、参考和 NUC 查表的夜间逆向结论。 |
| `analysis/handoff_20260813.md` | 黑洞、SBNUC、Hardie/Kalman 路线的历史总结。 |
| `analysis/pairs_nuc2/` | 官方 NUC 同帧数据。 |
| `analysis/pairs_move/` | 官方移动目标数据。注意旧 `.gain/.thr` 曾被覆盖。 |
| `analysis/pairs_recheck_20260811/` | 使用修复后的 `tsdk_pair2_fixed.exe` 重新捕获的数据,包含未覆盖的真实 `.gain/.thr`。 |
| `analysis/pairs_long/` | 较长时间官方抓帧和内部缓冲。 |
| `analysis/pairs_ffc/``pairs_ffc2/` | FFC 前后对比。 |
| `analysis/pairs_win/``pairs2/``pairs_bar/` | 窗口、调色板和官方输出实验。 |
| `analysis/captures/` | USBPcap、libusb shim 和官方/csdk 抓包。 |
| `analysis/usbnoise/` | 原始噪声帧和元数据。 |
| `analysis/ourdump/` | 直连设备原始抓帧。 |
| `analysis/reverse-cache/` | AAR、JAR 等解包后的逆向缓存。 |
| `analysis/reverse_tools/` | ARM64/ELF 辅助工具。 |
| `analysis/revtools.py` | ELF 加载、符号、交叉引用辅助脚本。 |
| `analysis/t2e_table.json` | T2E 单调表。 |
| `analysis/official_t2e_table.txt` | 官方 T2E 提取文本。 |
| `analysis/legacy-cpp/` | 被纯 C SDK 替代的旧 C++ 实现和构建物。 |
| `analysis/demo2_*.png` | 历史实机验证截图。 |
### 3.4 `build-artifacts/`
该目录保存可直接运行的 Windows 程序、DLL、抓图、日志和实验产物。当前最重要的文件:
- `mag160c_demo3.exe`:当前 demo3。
- `mag160c_official_nuc_gain.bin`:官方三段 gain/off 表,230400 字节。
- `mag160c_official_nuc_thr.bin`:官方 threshold 抓取文件,115200 字节;demo3 实际使用前 76800 字节中的两个 threshold/像素,尾部多余数据保留作证据。
- `tsdk_pair2_fixed.exe`:修复 `.gain/.thr` 覆盖问题的官方抓帧工具。
- `demo3_diag.txt`demo3 每帧诊断日志。
- `demo3_ffc.txt`FFC 调度日志。
- `demo3_rebase.txt`FFC 后参考 rebase 日志。
- `demo3_auto_*.bmp`demo3 每 30 帧自动抓图。
- `official_*.bin``official_*.rgb``official_meta.txt`:官方活体输出样本。
- `csdk_*``mag160c_*``usb_*``tsdk_*`:历史测试和探针程序。
不要把 `build-artifacts` 当成唯一源代码目录。多数文件是从不同历史版本生成的,必须结合时间、文件名和日志判断是否属于当前版本。
## 4. 硬件和 USB 环境
### 4.1 设备身份
```text
VID = 0x833C
PID = 0x0001(常见值,具体以设备描述符为准)
分辨率 = 160×120
帧像素数 = 19200
常见帧率 = 15 fps
```
### 4.2 Windows 直连端点
| 端点 | 方向 | 用途 |
|---|---|---|
| `0x03` | 主机到设备 | 命令写入。 |
| `0x82` | 设备到主机 | 命令响应。 |
| `0x81` | 设备到主机 | 实时帧。 |
| `0x84` | 设备到主机 | 大块数据或 DDT 相关读取,当前 demo3 不依赖。 |
### 4.3 原始帧布局
EP `0x81` 数据以固定标记开始:
```text
+0x00 u32 0x1BB1B11B
+0x04 u32 帧计数
+0x08 u32 数据长度,160×120 时为 0x9600
+0x0C u32 帧类型,0 或 1
+0x10 u32 shutter/周期字段
+0x1C 38400 字节像素,19200 个小端 uint16
+0x1C+len u32 0x1BB1B11C
```
demo3 的第二次 bulk read 直接从 `data[0]` 读取 38400 字节像素;第一段 28 字节头已在 `hdr` 中读取。这是曾经修复过的关键偏移问题。
### 4.4 命令序列
当前设备实测的初始化序列:
```text
0x6BB6B66B4 字节
0x6BB6B66C4 字节
0x6BB6B66F4 字节
0x6BB6B672,参数 0,8 字节,通常连续发送两次
等待约 300 ms
0x6BB6B6734 字节,启动
```
停止:
```text
clear_halt(0x03)
clear_halt(0x82)
0x6BB6B6744 字节
```
FFC
```text
0x6BB6B672 + uint32 参数
```
不要把普通 4 字节命令误写成 8 字节;当前设备对普通命令的 8 字节形式可能 STALL。只有带参数的 FFC 使用 8 字节。
## 5. 官方 SDK 和反汇编成果
### 5.1 SDK 文件
原厂 SDK 主要在:
```text
IR_Camera_SDK-1.0.1/windows/windows/app/
IR_Camera_SDK-1.0.1/windows/windows/lib/x64/
IR_Camera_SDK-1.0.1/windows/windows/drivers/
IR_Camera_SDK-1.0.1/android/android/EloThermal/
IR_Camera_SDK-1.0.1/linux/1.2.2/1.2.2/EloThermal/
```
Windows 关键文件:
- `CoreSDKLib.dll`:底层 MAG API、USB 和渲染主链。
- `ThermalSDK.dll`:更高层的热像 API 包装。
- `libusb0.dll`:官方旧版 libusb-win32 路径使用。
- `CameraSDK.dll`:RGB/UVC 相机接口,不是红外原始帧主通道。
Android/Linux 版本提供了额外符号、JNI、C++ 类名和温度函数线索,对 ARM64 `libcoresdk.so` 的温度和校正逆向非常有帮助。
### 5.2 平滑器
通用平滑器函数大约位于 `0x1800011a0`
- mode=1:当前 f20 实例使用,逐帧复制输入,不是多帧 EMA。
- mode=2:两帧平均。
- mode=4:累计平均,当前 ref 启动阶段使用。
对象:
```text
dev+0x41ee0ref 平滑器对象
dev+0x41ef0ref 实际 uint16 缓冲指针
dev+0x41f10f20 平滑器对象
dev+0x41f20f20 实际 uint16 缓冲指针
dev+0x41fd8ref 相关 mode,实测为 4
dev+0x41fdcf20 相关 mode,实测为 1
dev+0x41fe0:后续可选处理模式,实测为 1
```
### 5.3 官方参考时序
启动帧计数和参数实测:
```text
0x2d78 = 4
0x2d88 = 5
0x2d8c = 4
0x2d90 = 1800
0x2d94 = 250
```
启动早期的 `c620 -> 0x41ee0` 推帧会形成 ref。正常处理帧不会每帧重新采集整幅 ref。FFC 会切换 type=1 校准帧,官方应用在这段时间冻结显示。
### 5.4 官方 NUC 查表
`0x180017200` 的关键反汇编已经确认:
```c
d2 = ((int)f20[i] - (int)ref[i]) >> 1;
seg = 0;
while (seg < nsegs - 1 && d2 > threshold[i][seg])
seg++;
gain = gainoff[seg][i].gain;
off = gainoff[seg][i].off;
out = off + ((gain * d2) >> 12);
out = clamp(out, 0, 65535);
```
实测:
```text
nsegs = 3
每像素 threshold 数 = 2
每段每像素是一个 uint16 gain + 一个 uint16 off
gain/off 表总大小 = 3 × 19200 × 4 = 230400 字节
threshold 实际需要 = 2 × 19200 × 2 = 76800 字节
shift = dev+0x11c = 12
```
本工程通过修复后的 `tsdk_pair2.c` 抓取 pair_000 表,并用 PowerShell 离线复算:
```text
官方 raw 与表公式重建的平均绝对误差约 0.118 counts
绝大多数像素完全一致
少量最大误差约 900 counts,来自后续盲元补偿尚未复刻
```
这是当前最可靠的官方 NUC 复刻证据。
### 5.5 NUC 表生成
相关函数:
```text
0x180016ae0:按 dev+0x54 传感器温度选择端点区间
0x180016dd0threshold 的 signed Q12 分段插值
0x180016f10gain/off 的 unsigned Q12 分段插值
0x18000c760:把表重建分成多个 chunk 逐步写入
```
端点来自 DDT/配置,不来自当前 live、ref 或场景。官方表在启动重建和 FFC 后重建阶段变化;同一个重建组内的连续普通帧通常相同。当前 demo3 使用一组静态官方表,因此 FFC 后和传感器温度区间变化时还不完全等价。
### 5.6 NUC 后处理
`0x180017330` 不是全帧 3×3 模糊,而是固定记录表驱动的盲元/坏点补偿:
- 只处理 `dev+0x41878` 指向的固定记录。
- 原地修改 `dev+0x270`
- 访问邻域像素并平均或按固定类型替换。
- 没有场景历史,也不负责整幅图去鬼影。
`0x18001e920` 可能是输出 temporal filter,但当前 `dev+0x41fe0=1` 时实测路径跳过,不能把它当成官方当前画面的主要鬼影来源。
### 5.7 窗口、灰度和调色板
- 官方窗口字段约为 `dev+0x4202c` / `dev+0x42030`
- 静态背景最小跨度约 624 counts,即半宽约 312。
- 有热目标时窗口会动态扩大。
- `dev+0x4284c` 有 1024 项灰度 LUT。
- `dev+0xb18` 有 256×4 BGR 调色板。
- 同帧重建实验已经证明窗口和 LUT 是当前帧确定性映射,不保存上一帧历史,显示层不是大片鬼影的主要来源。
### 5.8 官方温度
demo3 采用已从官方提取的 T2E 表:
```text
temp_mC = T2E[3 * nuc - C]
C 约为 5797,实际会话相关
```
主要代码在 `counts_to_temp_mc()`。T2E 数据在:
- `csdk/include/mag160c_official_t2e.h`
- `analysis/t2e_table.json`
- `analysis/official_t2e_table.txt`
## 6. 当前 demo3 代码思路
### 6.1 输入和坏点
`decode_live()`
1. 从第二次 bulk read 的 `data[0]` 解析 19200 个小端 `uint16`
2. 如果启用固定坏点表则执行拓扑填充;当前 `BADMAP_ENABLE=0`,避免动态场景坏图钉在屏幕坐标。
3. 执行 `correct_zero_pixels(g_live)`,修复原始零值。
### 6.2 参考采集
- 启动 FFC 后等待基线稳定。
- `REF_INIT_N=12` 帧采集。
- 每像素收集样本并做排序和中间 50% 平均。
- 结果放入 `g_ref_mura`
- `g_ref_mura` 同时承担固定 mura 图案和启动场景基线,这是当前低温残影的根本风险之一。
### 6.3 官方表加载
`load_official_nuc_tables()` 从程序工作目录加载:
```text
mag160c_official_nuc_gain.bin
mag160c_official_nuc_thr.bin
```
`official_nuc_value()` 按官方公式选择每像素 segment 并计算输出。
### 6.4 全局偏置
`calibrate_official_ref_bias()`
- 每帧抽取每 4 个像素中的一个。
- 对候选 scalar bias 计算官方 NUC 输出直方图中值。
- 二分搜索,使输出中值接近 `NUC_CENTER=9804`
- 使用 `g_ref_mura + g_official_ref_bias` 作为查表参考。
这个步骤只跟踪全局漂移,不应把局部场景写进逐像素参考。
### 6.5 当前 SBNUC 实验分支
当前 `SBNUC_ENABLE=1` 的实际更新约束:
- 正残差不更新参考。
- 运动期间创新门控保持约 6 帧,不更新参考。
- 负残差需要运动结束后连续 2 帧低于 `SB_RECOVER_T=16`
- 还要求该像素之前处于 `SB_HOT_RELEASE`,也就是曾经为热态、随后离开。
- 低温物体从头到尾的负残差不应进入自愈,避免移开后亮鬼影。
这仍是实验代码。旧的 `g_hot_hist``g_sb_prev_d``g_sb_innov_var` 等数组和注释中保留了多轮失败方案,后继者应在确认新方案后清理,而不是继续叠加状态。
### 6.6 设置参考按钮
当前按钮文字是 `Recenter bias`,对应 `WM_COMMAND``1004`
- 如果官方表可用,只重新计算全局 bias。
- 不再执行 `g_ref_mura[i] = g_live[i]`
- 这是刚修复的严重问题;旧行为会把当前物体温度写进参考,导致设置参考后所有物体趋于相同,挪开后才出现高温/低温差异。
- 没有官方表时才保留旧的 fallback 手动参考行为。
## 7. 已解决的问题
以下问题在历史实机验证中已经明显改善,不要在没有证据时推翻:
| 问题 | 原因 | 当前处理 |
|---|---|---|
| 颗粒感很重 | demo2 早期 NUC 斜率过大,曾使用接近 3 的斜率 | 当前线性 fallback 为 `NUC_GAIN=19`,官方表路径已接入。 |
| FFC 后颜色跳变 | FFC 后重新采集场景参考,把场景写进 ref | `REF_REINIT_AFTER_FFC=0`,type=1 不渲染,使用全局 rebase。 |
| 物体破碎、椒盐 | 固定窗口过窄 | 使用 P2..P98 自适应窗口和最小 624 跨度。 |
| mura 蒙层 | 常数参考或错误平场直接显示传感器固定纹理 | 启动采集 `g_ref_mura`,并使用逐像素官方 NUC 表。 |
| 中上固定遮蔽 | 动态 badmap 将场景结构钉在屏幕坐标 | `BADMAP_ENABLE=0`。 |
| 右下炫光 | 把盲元补偿误当全帧 3×3 blur | 删除错误整帧 blur 路径。 |
| 最高温点黑色 | 极值映射和零值处理不稳 | `idx >= hi` 饱和到 1023,保留零值修复。 |
| 黑洞完全不消失 | 参考冻结且没有任何失配处理 | 当前保留受限的 post-motion self-heal,但仍有速度/误判权衡。 |
| 设置参考后物体被抵消 | 按钮把当前 live 整帧覆盖到 ref | 改为 `Recenter bias`,不覆盖固定平场。 |
## 8. 已经尝试且效果不好的路线
### 8.1 单纯调 SBNUC 全局参数
尝试过:
- 去掉帧差条件。
- 放宽 `dd` 阈值。
- `alpha``1/64` 调到 `1/16`
- 统一使用更快负残差步长。
结果:黑洞在某些情况下改善,但小温差或低温物体会被参考吸收,移开后残影回来;过激时画面稳定性变差。
### 8.2 显示层去鬼影
尝试过:
- 最近热区 mask。
- motion history。
- recent hot mask。
- 显示层邻居替换。
- `deghost_nuc()`
结果:容易把真实目标抹掉,出现“有地方看不见”的副作用。当前调用被注释,后继者不要重新走这条路线。
### 8.3 复杂 MOG/自愈状态机
尝试过:
- 逐像素 warm/release 状态。
- 时域创新方差。
- 运动保持计数。
- persistent negative self-heal。
结果:可以在黑洞和鬼影之间移动问题。根本原因是一个 `g_ref_mura` 同时承载固定平场、场景基线和自适应背景,信息角色混在一起。
### 8.4 完全冻结参考
效果:热目标鬼影明显减少或消失。
副作用:当场景基线或局部低温发生变化时,旧位置会形成黑洞;黑洞自愈又可能吸收低温物体。这个折中证明需要拆分“固定传感器校正”和“场景背景模型”,而不是继续改一个 ref。
### 8.5 静态官方表
效果:比单一 `0.19 + comp` 更接近官方,热目标鬼影有明显改善。
局限:
- 表来自某次官方会话,FFC/传感器温度变化后官方会重新插值。
- `0x180017330` 固定盲元补偿没有完整接入。
- 表外的参考时序、内部 sensor temperature 和端点配置没有完全复刻。
- 当前静态表不是最终官方复刻。
## 9. 当前未解决问题和最重要的下一步
### 9.1 低温长停留残影
现象:
- 低温区域在画面中停留较长时间。
- 参考或负残差处理可能逐渐改变局部基线。
- 物体移动后出现残影,或者黑洞与亮鬼影互换。
最可能的根因:
1. demo3 的 `g_ref_mura` 仍然是“固定平场 + 启动场景”混合物。
2. post-motion self-heal 对“曾热后变冷”和“从头到尾低温”虽然已区分,但低对比度转换可能漏过状态阈值。
3. 官方表当前是静态表,FFC/温度区间变化没有实时重建。
4. 官方盲元补偿没有完全复刻,少量异常像素可能形成黑点或局部结构。
5. 官方的实际 ref 绝对偏置和 demo3 的 `g_ref_mura + scalar bias` 不是同一个参考定义。
### 9.2 优先任务 A:复刻官方动态 NUC 表
需要继续做:
1.`tsdk_pair2_fixed` 保存的 `b01/b02/b04/b05` 端点源表中确认 DDT 端点记录结构。
2. 找到 USB 原始帧或设备状态中对应 `dev+0x54` 的传感器温度。
3.`0x180016ae0``0x180016dd0``0x180016f10` 的 Q12 整数公式,在 demo3 中按温度插值生成 threshold/gain/off。
4. FFC 后重新生成表,但不重新把场景采入空间参考。
5. 用多温度、多次 FFC 的官方 `b03/b06``raw` 做逐像素回归。
### 9.3 优先任务 B:复刻官方盲元补偿
需要从官方活体捕获:
- `dev+0x41878` 固定记录表。
- `dev+0x41654` 对应的记录数量。
- 每条记录的目标像素、类型和邻域索引。
然后把 `0x180017330` 的原地邻域补偿接到官方 NUC 表输出后。不要使用由场景动态生成的 badmap。
### 9.4 优先任务 C:拆分参考角色
推荐最终数据结构:
```text
g_fixed_pattern[i] 只保存传感器固定空间校正
g_scene_reference[i] 可选、严格受状态控制的场景背景
g_global_ref_bias 全局传感器/FFC 漂移
g_official_nuc_table 官方温度配置表
```
当前 `g_ref_mura` 不应继续同时承担上述所有角色。
### 9.5 优先任务 D:受控实验数据
必须抓以下序列,每个序列至少 60 帧,最好包括 live/ref/raw/gain/thr/gray
1. 空背景稳定 10 秒。
2. 热目标进入、停留、离开、空背景恢复。
3. 冷目标进入、停留、离开、空背景恢复。
4. 小温差热目标重复移动。
5. FFC 前后同一目标序列。
对每个像素同时画:
```text
live
ref
live-ref
d2
official raw
demo3 raw
gray
```
不要只看 BMP。BMP 只能说明最终表现,不能定位残影是在 USB、ref、NUC、盲元补偿还是窗口阶段产生。
## 10. 环境安装和部署
### 10.1 当前开发环境
当前主要环境是 Windows PowerShell
```text
工作目录:C:\Project\MAG160C
MinGW GCCC:\mingw64\bin\gcc.exe
GCC 版本:曾使用 14.2.0
Python:用于 PDF、二进制和逆向辅助
JavaZulu 21,用 javap 查看 Android 类
Git:用于提交和远端同步
Git LFS:用于大型二进制
```
### 10.2 必装工具
建议安装或确认以下工具:
1. MinGW-w64,要求 `gcc``g++``ar``objdump``readelf``strings``dlltool``gendef` 可用。
2. Git。
3. Git LFS。
4. Python 3.10 或更新版本。
5. Java 21 或可用的 `javap`,仅在需要分析 Android JAR/AAR 时使用。
6. PowerShell 5.1 或 PowerShell 7。
7. 可选:CMake。当前环境中 `cmake` 不在 PATH,因此实际验证主要使用 GCC 直接命令。
8. 可选:Wireshark 4.6.7 和 USBPcap 1.5.4,用于 USB 抓包。
9. 可选:Zadig,用于切换 WinUSB/libusb-win32 驱动。
### 10.3 Python 逆向包
历史上使用过:
- `capstone`
- `pyelftools`
- `pdfplumber`
工程中已有 `.tools/python-revlibs/`,不要假设系统 Python 一定有这些包。需要时可以先检查:
```powershell
python --version
python -c "import capstone, elftools; print('逆向 Python 包可用')"
```
### 10.4 SDK 和 DLL
原厂文件已经随工程提供,通常不需要再次下载:
```text
IR_Camera_SDK-1.0.1\windows\windows\app\CoreSDKLib.dll
IR_Camera_SDK-1.0.1\windows\windows\app\ThermalSDK.dll
IR_Camera_SDK-1.0.1\windows\windows\app\libusb0.dll
IR_Camera_SDK-1.0.1\windows\windows\lib\x64\CoreSDKLib.dll
IR_Camera_SDK-1.0.1\windows\windows\lib\x64\ThermalSDK.dll
csdk\third_party\libusb\win64\libusb-1.0.dll
csdk\third_party\libusb\win64\libusb-1.0.x64.a
```
官方 `ThermalSDK.dll` 路径和 demo3 的 libusb-1.0 路径不要混用。官方程序通常依赖 `libusb0.dll`/libusb-win32demo3 使用 `libusb-1.0.dll` 和 MinGW 导入库。
### 10.5 驱动注意事项
曾经验证过的 Windows 组合:
- 原厂旧驱动签名在新 Windows 上可能失败。
- Zadig 安装 WinUSB 或 libusb-win32 后,设备才能被对应程序打开。
- 官方 DLL、TI 的 64 位 `libusb-1.0.dll`、WinUSB/libusb-win32 的组合行为不同。
- 不要在官方程序、`tsdk_pair2` 和 demo3 同时占用设备。
- 如果出现 `no channel`、STALL、设备不枚举,先停止所有程序并重新插拔 USB。
## 11. 构建和启动
### 11.1 demo3 当前编译命令
在 PowerShell 中执行:
```powershell
```
注意:命令只允许出现一次 `mag160c_error.c`。重复传入会出现 `multiple definition` 链接错误。
### 11.2 启动 demo3
```powershell
Stop-Process -Name mag160c_demo3 -Force -ErrorAction SilentlyContinue
Start-Process "C:\Project\MAG160C\build-artifacts\mag160c_demo3.exe" -WorkingDirectory "C:\Project\MAG160C\build-artifacts"
```
官方 NUC 表文件必须和 exe 在同一个工作目录中:
```text
build-artifacts\mag160c_official_nuc_gain.bin
build-artifacts\mag160c_official_nuc_thr.bin
```
如果缺失,程序会退回旧的线性 NUC 路径,画面和残影表现不能与当前版本比较。
### 11.3 停止 demo3
```powershell
Stop-Process -Name mag160c_demo3 -Force -ErrorAction SilentlyContinue
```
必须先停止 demo3 才能运行官方 ThermalSDK 抓帧工具。
### 11.4 编译修复后的官方抓帧工具
`tsdk_pair2.c` 原来先保存真实指针表,后面又覆盖同名 `.gain/.thr`。当前修复版把后面的内联字段改存为 `.gain_inline/.thr_inline`
```powershell
```
### 11.5 官方抓帧
先确认输出目录父目录存在,再执行:
```powershell
New-Item -ItemType Directory -Path "C:\Project\MAG160C\analysis\pairs_recheck_20260811" -Force
Stop-Process -Name mag160c_demo3 -Force -ErrorAction SilentlyContinue
& "C:\Project\MAG160C\build-artifacts\tsdk_pair2_fixed.exe" "C:\Project\MAG160C\analysis\pairs_recheck_20260811" 12 6000
```
参数含义:
```text
参数 1:输出目录
参数 2:抓取 pair 数
参数 3:官方 SDK 初始化等待毫秒数
```
`tsdk_pair2.c` 当前会在约三分之一和三分之二位置触发 FFC,适合验证 FFC 表变化,不适合完全无干预的纯运动实验。要做低温残影实验,建议另写不自动触发 FFC 的 harness。
### 11.6 日志和图像
demo3 工作目录下:
```text
```
日志文件由程序重新启动时以写模式打开,重启会覆盖旧日志。要保留一轮实验,先复制到 `analysis/` 并改名。
## 12. C SDK 构建和验证
如果已经安装 CMake
```powershell
cmake -B build -S csdk
cmake --build build
ctest --test-dir build
```
当前机器没有 CMake 时,按照 `csdk/WINDOWS_TESTING.md` 使用 MinGW 直接编译。无硬件时可以验证:
```powershell
build-artifacts\csdk_cli_libusb.exe frame-test
build-artifacts\csdk_cli_libusb.exe temp-test
build-artifacts\csdk_cli_libusb.exe tcm-rotate 5
build-artifacts\csdk_cli_libusb.exe tcm-light green blink
build-artifacts\csdk_cli_libusb.exe ir-info
```
预期 TCM 编码结果示例:
```text
7e 00 07 85 02 77 00 01 00 05 7f
```
## 13. Git 和仓库维护
本工程原先只有空的 `.git` 目录,不是有效 Git 仓库。本次移交应初始化真实 Git 仓库并推送到:
```text
https://git.zxcli.top/zxc/MAG160C.git
```
仓库约 0.824 GB,包含大量 DLL、EXE、APK、PDF、PNG、BMP、抓帧和反汇编二进制。已准备 Git LFS 规则。提交前必须检查:
```powershell
```
不要把账号密码、访问令牌、私钥写入文档或代码。原厂 SDK 和 APK 可能受第三方许可限制,仓库接手者应确认仓库访问权限和内部使用范围。
## 14. 当前接手者的建议工作顺序
### 第一步:确认环境和版本
1. 阅读本文、`analysis/handoff_20260813.md``analysis/handoff_20260811_full.md`
2. 检查 `git status` 和远端分支,确认没有并行改动。
3. 检查设备 PID、驱动、DLL、表文件。
4. 编译并启动当前 demo3,保存一轮不移动时的日志。
### 第二步:验证当前路径是否真的加载官方表
1. 暂时把 `mag160c_official_nuc_gain.bin` 改名,启动一次并记录 fallback 画面。
2. 恢复表文件,再启动并记录官方表画面。
3. 比较 `demo3_diag.txt``g_sb_shift`、NUC 统计和 BMP。
4. 不要用缺失表文件的 fallback 版本评价当前算法。
### 第三步:做官方和 demo3 同帧采集
1. 停 demo3。
2. 用修复后的官方工具抓取至少 60 帧,不要自动触发 FFC。
3. 保存 f20、ref、raw、gain、thr、gray、window、blind compensation 记录。
4. 用脚本逐像素对比官方 raw 和 demo3 raw。
### 第四步:优先修官方动态表和盲元补偿
不要先改调色板、窗口、显示层。官方证据已经说明这两个阶段没有上一帧历史,低温残影优先查 ref、gain/off、threshold、FFC 表重建和盲元补偿。
## 15. 给下一位 AI 的接手提示词
下面的提示词可以直接复制给下一位 AI。它要求 AI 先理解工程,再动手,不要从头重做,也不要反复尝试已经失败的显示层补丁。
```text
你现在接手 C:\Project\MAG160C 的 MAG160C 热像仪逆向工程。
设备:MAG160C160x120USB VID 0x833C,常见 PID 0x0001。
主程序:C:\Project\MAG160C\csdk\tools\mag160c_demo3.c
输出程序:C:\Project\MAG160C\build-artifacts\mag160c_demo3.exe
官方 DLLIR_Camera_SDK-1.0.1\windows\windows\app\CoreSDKLib.dll 和 ThermalSDK.dll
远端仓库:https://git.zxcli.top/zxc/MAG160C.git
严格执行以下步骤:
1. 先读:
- 交接_完整逆向工程说明_20260811.md
- analysis/handoff_20260813.md
- analysis/handoff_20260811_full.md
- analysis/protocol_spec.md
- csdk/tools/mag160c_demo3.c
- csdk/tools/tsdk_pair2.c
2. 再检查:
- git status --short --branch
- build-artifacts/mag160c_official_nuc_gain.bin
- build-artifacts/mag160c_official_nuc_thr.bin
- analysis/pairs_recheck_20260811/
- analysis/disasm/
3. 先理解已经确认的官方事实:
- EP 0x03 是命令 OUTEP 0x82 是响应 INEP 0x81 是帧流。
- 帧 marker 是 0x1BB1B11B,像素从帧内 +0x1c 开始,160x120 uint16 LE。
- f20 平滑器 dev+0x41f10 当前 mode=1,正常帧基本直接复制,不是隐藏 EMA。
- ref 在 dev+0x41ef0,启动/FFC 平滑器 mode=4 形成,正常显示帧不逐帧重采集。
- NUC 0x180017200 使用 d2=(f20-ref)>>1、每像素两个 signed threshold、三段 gain/off、Q12 乘法和 clamp。
- 0x180017330 是固定盲元邻域补偿,不是全帧 3x3 blur。
- 0x18001e920 当前 mode=1 通常跳过,不要假设官方有开启的 temporal filter。
- 官方 gain/off/threshold 表由传感器温度、DDT 配置和 FFC 重建生成,不读取 scene/live/ref。
4. 当前 demo3 的真实状态:
- 已接入一组官方活体抓取的静态 gain/off/threshold 表。
- 用输出域中值反求全局 ref bias。
- SBNUC 只允许曾经热、后来负残差的像素自愈;低温从头到尾的负残差不应更新参考。
- 显示层 deghost_nuc() 不调用,BADMAP_ENABLE=0,窗口、LUT、palette 不要随意改。
- 低温区域长时间停留仍有残影,说明问题尚未解决。
5. 当前首要研究目标:
- 查清低温静止目标的残影是在 raw/live、ref、d2、官方 gain/off、盲元补偿还是窗口前产生。
- 不能只看 BMP;必须逐像素保存和比较 live/f20/ref/d2/raw/gray。
- 建立官方和 demo3 的 60 帧以上同场景数据集,覆盖热目标和冷目标。
- 复刻官方 gain/off/threshold 温度端点插值和 FFC 后表重建。
- 复刻固定盲元补偿记录表,不能用场景动态 badmap 代替。
6. 已经失败、不要盲目重复的路线:
- 显示层 motion history、recent hot mask、邻域替换。
- 单纯把 SBNUC 全局 alpha 调快。
- 把所有负残差都快速写回参考。
- 把所有正负残差都用一个 MOG 参考吸收。
- 随意修改窗口、调色板、FFC 周期和 BADMAP_ENABLE。
7. 修改原则:
- 先保留当前已验证的官方查表、窗口、LUT、palette 和 USB 链路。
- 只在有反汇编或抓帧证据的地方修改。
- 不回退用户已经确认有效的修复。
- 所有手工编辑使用 apply_patch。
- 修改后使用用户给出的 GCC 命令编译,并启动 demo3 让用户实测。
- 不要声称“已修复”,除非有用户实机反馈或可复现的同帧数据证据。
8. 编译命令:
gcc -O2 -w -DMAG160C_STATIC -I"C:\Project\MAG160C\csdk\third_party\libusb\win64" -I"C:\Project\MAG160C\csdk\include" -I"C:\Project\MAG160C\csdk\src" -o "C:\Project\MAG160C\build-artifacts\mag160c_demo3.exe" "C:\Project\MAG160C\csdk\tools\mag160c_demo3.c" "C:\Project\MAG160C\csdk\src\mag160c_display.c" "C:\Project\MAG160C\csdk\src\mag160c_error.c" "C:\Project\MAG160C\csdk\third_party\libusb\win64\libusb-1.0.x64.a" -lgdi32 -luser32
9. 启动命令:
Stop-Process -Name mag160c_demo3 -Force -ErrorAction SilentlyContinue
Start-Process "C:\Project\MAG160C\build-artifacts\mag160c_demo3.exe" -WorkingDirectory "C:\Project\MAG160C\build-artifacts"
10. 你的第一条回复不要直接提方案。先返回:
- 你读过的文件。
- 当前官方链路理解。
- 当前 demo3 链路理解。
- 低温残影的证据缺口。
- 下一轮最小可验证实验。
然后再开始修改或抓帧。
```
## 16. 交接结束条件
下一位接手者在以下条件都满足前,不应把项目标记为完成:
1. 官方和 demo3 的 60 帧以上同帧 raw/ref/NUC 对比完成。
2. 热目标和冷目标的进入、停留、离开都没有明显残影。
3. FFC 前后表重建、窗口和显示冻结行为与官方一致。
4. 固定盲元补偿记录已复刻,异常零点和少量极端 outlier 消失。
5. 不依赖显示层遮罩,不牺牲真实目标,不产生黑洞。
6. 用户在实机上确认低温和小温差场景都达到可接受效果。