Files
ZXCLI 5c22bfe78c 新增平台无关渲染模块 mag160c_render + Linux 参考程序 + 移植评估文档
- csdk/include/mag160c/mag160c_render.h + csdk/src/mag160c_render.c:
  官方渲染管线(快门提取/FFC 状态机/ref 采集/表重建/NUC/盲元/窗口/
  LUT(0x8c)/gray/2x/调色板)封装为无平台依赖 API,FFC 命令经回调发出
- csdk/tools/mag160c_linux_demo.c:Linux 风格参考程序(libusb + render
  API + 显示后端抽象 fbdev/DRM/LVGL),Windows 可编译验证(BMP 输出)
- 修复帧组装:第二段 bulk 读 38428B(像素+尾),尾部含快门字
  实测 shutter=31492 sel=2 stats 正常
- docs/linux_port_plan.md:芯片选型(推荐 T113-S3 QFP128 非 BGA ~20元)、
  动画库(LVGL+rlottie 参考 LiThermal)、显示方案、接口抽象设计
- csdk/README 增加 Linux 移植章节
2026-08-14 17:08:38 +08:00

288 lines
12 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 C SDK (csdk/)
MAG160C 热像仪(160×120USB VID 0x833C)的纯 C 重新实现,基于对原厂
Windows/Linux/Android SDK 的完整逆向(见 `../analysis/reverse_20260813_full.md`)。
包含:USB 会话层、帧解析/流组装、温度换算、TCM 板通信、以及**官方渲染管线的
逐像素复刻**demo3 v5)。
## 目录结构
```
csdk/
include/mag160c/
mag160c.h 公共 C ABI(错误域、协议常量、帧格式、温度、TCM)
mag160c_display.h FFC 调度器 + 显示辅助(ref rebase 等)
src/
mag160c_internal.h 内部共享(last-error
mag160c_error.c TLS last-error + 错误名
mag160c_frame.c 0x1bb1b11b 帧解析 + 流组装器
mag160c_temp.c Calibration / ConvertResponse2Temperature / T2E
mag160c_tcm.c FTDICommand 0x7e 组帧 + 旋转/指示灯构建
mag160c_ir.c libusb 会话(link/start/stop/ffc/info/回调/FFC调度)
mag160c_display.c 显示辅助(FFC 调度器、ref rebase、坏点)
mag160c_tables.h T2E/E2TAccQ10 温度表(从二进制提取)
mag160c_official_*.h 官方调色板 / LUT1024 / T2E(从官方活体抓取导出)
tools/
mag160c_demo3.c 主程序:官方管线复刻(DDT+NUC+盲元+窗口+LUT+2x
tsdk_pair2.c 官方 ThermalSDK 同帧抓帧工具(含表/盲元/快门)
tsdk_pair3.c 增强采集(DDT 复制、完整端点表、盲元、h1024/cdf)
mag160c_cli.c CLIir-info/ffc/start/stop/tcm-rotate/tcm-light 等
mag160c_csdk_stream_test.c csdk 流测试
legacy/ 历史探索工具(归档,勿用)
tests/ test_frame / test_temp / test_tcm / test_api / test_display
CMakeLists.txt CMake 构建(可选;当前环境直接用 gcc)
WINDOWS_TESTING.md Windows 硬件测试指南(USBPcap/Wireshark/MinGW
```
## 构建
### 方式 A:直接 GCC(当前 Windows 环境)
```powershell
# CLI 工具
gcc -O2 -w -DMAG160C_STATIC -I"csdk\third_party\libusb\win64" -I"csdk\include" -I"csdk\src" `
-o build-artifacts\mag160c_cli.exe csdk\tools\mag160c_cli.c `
csdk\src\mag160c_ir.c csdk\src\mag160c_frame.c csdk\src\mag160c_temp.c `
csdk\src\mag160c_tcm.c csdk\src\mag160c_error.c csdk\src\mag160c_display.c `
csdk\third_party\libusb\win64\libusb-1.0.x64.a
# 主程序 demo3(官方管线复刻)
gcc -O2 -w -DMAG160C_STATIC -I"csdk\third_party\libusb\win64" -I"csdk\include" -I"csdk\src" `
-o build-artifacts\mag160c_demo3.exe csdk\tools\mag160c_demo3.c `
csdk\src\mag160c_display.c csdk\src\mag160c_error.c `
csdk\third_party\libusb\win64\libusb-1.0.x64.a -lgdi32 -luser32
# 官方抓帧工具
gcc -O2 -w -o build-artifacts\tsdk_pair3.exe csdk\tools\tsdk_pair3.c
```
libusb 依赖:`csdk/third_party/libusb/win64/`(头文件 + DLL + MinGW 导入库)。
### 方式 BCMake(有 CMake 时)
```powershell
cmake -B build -S csdk
cmake --build build
ctest --test-dir build
```
无 libusb-1.0 时,IR 会话 API 返回 `MAG160C_ERR_NOT_SUPPORTED`;纯计算
(帧解析、温度、TCM)和对应测试无依赖可跑。
## 快速开始
### 1. 连接并启动(核心 API 流程)
```c
#include <mag160c/mag160c.h>
#include <mag160c/mag160c_display.h>
static void on_frame(uint32_t idx, const uint8_t *data, size_t len, void *user) {
/* data: 完整帧(0x1c 头 + 像素)。用 mag160c_frame_parse 解析。 */
mag160c_frame_header_t hdr;
const uint16_t *pixels;
if (mag160c_frame_parse(data, len, &hdr, &pixels) == MAG160C_OK && hdr.frame_type == 0)
; /* pixels[19200] 小端 uint16160×120 */
}
int main(void) {
mag160c_ctx_t *ctx = NULL;
mag160c_ir_t *ir = NULL;
mag160c_init(&ctx);
mag160c_ir_open(ctx, &ir); /* 自动找 VID 0x833cconfig 2interface 0 */
mag160c_ir_prepare(ir); /* 66b/66c/66f + FFC(0)x2 + 300ms */
mag160c_ir_set_frame_callback(ir, on_frame, NULL);
/* 官方 FFC 节律(周期 1800 帧 / 间隔 9),保持 type=0 流稳定 */
static mag160c_ffc_scheduler_t sched;
mag160c_ffc_scheduler_init(&sched, 1800, 9);
mag160c_ir_set_ffc_scheduler(ir, &sched, 0);
mag160c_ir_start(ir); /* 线程收帧 + 0x6bb6b673 */
/* ... 收帧 / 读温度 ... */
int32_t temp_mc = 0;
mag160c_ir_read_temperature(ir, 80, 60, &temp_mc);
mag160c_ir_stop(ir);
mag160c_ir_close(ir);
mag160c_shutdown(ctx);
return 0;
}
```
### 2. 关键 API
| API | 说明 |
|---|---|
| `mag160c_ir_open/close` | USB 设备会话 |
| `mag160c_ir_prepare` | 官方初始化命令序列 |
| `mag160c_ir_start/stop` | 起停流(0x6bb6b673 / 0x6bb6b674|
| `mag160c_ir_trigger_ffc(param)` | 手动 FFC0 或 1|
| `mag160c_ir_set_ffc_scheduler` | 挂官方节律 FFC 调度器 |
| `mag160c_ir_set_frame_callback` | 每帧回调(解析后数据)|
| `mag160c_ir_read_temperature(x,y,&t)` | 探针温度(毫摄氏度×100|
| `mag160c_frame_parse` | 纯解析:marker/计数/类型/像素指针 |
| `mag160c_frame_stream_*` | 流组装器(乱序/分包恢复)|
| `mag160c_temp_calibrate` | 官方逐像素分段线性校准(NUC 温度域)|
| `mag160c_temp_convert_response` | 自动增益线性换算 |
| `mag160c_temp_t2e_interp` | T2E 曲线 Q13 插值 |
| `mag160c_tcm_*` | TCM 板 FTDICommand 0x7e 帧(旋转/指示灯)|
错误码域 `mag160c_error_t` 与官方 errno 域 `0xE4AE0001..` 对齐;
`mag160c_last_error()` 取线程局部最近错误字符串。
### 3. CLI 用法(mag160c_cli.exe,无硬件可跑纯计算)
```powershell
build-artifacts\mag160c_cli.exe ir-info # 枚举/信息
build-artifacts\mag160c_cli.exe frame-test # 帧解析自测
build-artifacts\mag160c_cli.exe temp-test # 温度换算自测
build-artifacts\mag160c_cli.exe tcm-rotate 5 # TCM 旋转指令编码
build-artifacts\mag160c_cli.exe tcm-light green blink # TCM 指示灯指令编码
```
### 4. 主程序 demo3(官方渲染管线复刻)
`tools/mag160c_demo3.c` 是当前维护的 Windows 直连演示/研究程序,逐像素复刻
CoreSDKLib.dll 的完整链路:
```
USB帧(type=0) → 快门提取(帧尾字) → FFC状态机(0x9ee0)
→ 端点选择+Q12插值(0x16ae0/0x16dd0/0x16f10, 快门驱动)
→ ref = FFC窗口4个type=1帧均值(0x41ee0 mode=4)
→ NUC查表(0x17200) → 盲元补偿(0x17330, 32条固定记录)
→ [可选后处理: temporal 0x1e920 / 帧差 0x175a0 / 隔行平滑 0x184f0/0x18660]
→ 统计+窗口(0x10780/0x109c0, half=312) → LUT1024重建(0x11ee0, 含0x8c)
→ 灰度+2x升采样(0x19740) → 官方调色板
```
#### 官方附加环节编译开关(默认 0 = 官方当前会话行为)
官方 SDK 中这些路径编译在内但当前会话控制字段为 0(未执行)。demo3
全部移植,用编译开关启用,运行时用按键切换测试:
| 开关 | 对应官方函数 | 官方字段 | 按键 |
|---|---|---|---|
| `OFF_IMPL_230` | 帧差调整 0x175a0 | 0x230=0 | 8 |
| `OFF_IMPL_41FE8` | 隔行平滑 0x184f0(2x)/0x18660(4x) | 0x41fe8=0 | 0 |
| `OFF_IMPL_30` | gray 覆盖 0x17770(auto)/0x17c40(manual) | 0x30=0, 0x84 | 9 |
| `OFF_IMPL_UPSCALE` | Nx 升采样 4x/8x | 当前 2x | — |
```powershell
# 默认版本(与官方行为一致)
gcc ... 见上文 demo3 编译命令
# 全部附加环节开启版(默认展示各路径,按键切回官方默认)
gcc -O2 -w -DOFF_IMPL_41FE8=1 -DOFF_IMPL_30=1 -DOFF_IMPL_230=1 -DMAG160C_STATIC ...
```
说明:
- 0x17770auto gray 双边滤波)的空间权重表在官方二进制 .data 节被裁剪
无法提取,demo3 用标准高斯核近似(σ=2.0),值域核按官方生成式(sqrt 核)。
- 0x17c40manual)已逐行翻译:8x8 窗口 4x4 采样对比度增强累积 → gray。
- 0x18660 为逐行翻译(4 相位加权插值);0x184f0 为 2-tap 半分辨率插值。
- 验证:默认版无回归;41fe8=1 开启后 NUC 输出 std 从 ~250 降到 ~95(平滑生效)。
运行(需要 `build-artifacts/` 下的 DDT 表文件):
```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"
```
依赖文件(放 exe 同目录):
| 文件 | 来源 |
|---|---|
| `mag160c_official.ddt` | 官方 DDT 校准文件(`%TEMP%\Core<序列号>` 副本)|
| `mag160c_official_nuc_gain.bin` | 官方 NUC gain/off 表(历史抓取,备用)|
| `mag160c_official_nuc_thr.bin` | 官方 NUC 阈值表(历史抓取,备用)|
| `libusb-1.0.dll` | libusb 运行库 |
验证状态(2026-08-14):
- NUC+盲元 与官方同帧抓帧逐像素 0/19200 误差
- 阈值/gain 插值 0 误差;2x 升采样 0/76800 误差;窗口公式与官方一致
- 同静态场景 320×240 RGB 直方图与官方相关性 0.98(跨会话)
- 显示层 = 官方同款 320×240(2x 平滑灰度 + 调色板 + HALFTONE 放大)
- 输出日志:`demo3_diag.txt`(每帧统计)、`demo3_ffc.txt`FFC 事件)、
`demo3_auto_*.bmp`(每 30 帧快照,320×240
### 5. Linux 移植(mag160c_render API
`include/mag160c/mag160c_render.h` + `src/mag160c_render.c` 是平台无关的
**官方渲染管线模块**:喂原始 USB 帧 → 输出 320x240 RGB24。内部完整实现
官方链路(快门提取→FFC 状态机→ref 采集→表重建→NUC→盲元→窗口→LUT→
gray→2x→调色板),FFC 命令通过回调发给调用方(调用方持有 USB 传输)。
```c
mag160c_render_cfg_t cfg = { .width = 160, .height = 120,
.ddt_path = "mag160c_official.ddt", .ffc_period = 1800,
.ffc_drift = 250, .startup_force_ffc = 1, .cdf_pivot_75 = 1,
.ffc_cb = my_ffc_sender, .ffc_user = NULL };
mag160c_render_init(&r, &cfg);
/* 每帧: */
mag160c_render_frame(r, full_frame_with_header, 1, rgb320x240);
```
`tools/mag160c_linux_demo.c` 是 Linux 风格参考程序(libusb + render API +
display 后端抽象,Windows 上也可编译运行,输出 thermal_*.bmp 验证)。
Linux 构建:
```bash
gcc -O2 -Wall csdk/tools/mag160c_linux_demo.c csdk/src/mag160c_render.c \
csdk/src/mag160c_ir.c csdk/src/mag160c_frame.c csdk/src/mag160c_temp.c \
csdk/src/mag160c_tcm.c csdk/src/mag160c_error.c csdk/src/mag160c_display.c \
-lusb-1.0 -lpthread -lm -o mag160c_linux_demo
```
显示后端(display_rgb 中)可按目标平台实现:fbdev / DRM-KMS / LVGL image。
UI 与动画建议:LVGL(界面/交互动画)+ rlottieLottie 特效),参考
LiThermal 项目;主控建议全志 T113-S3QFP128,非 BGA~20 元,G2D 2D
加速,Tina Linux)。完整评估见 `../docs/linux_port_plan.md`
### 6. 官方抓帧工具(tsdk_pair2 / tsdk_pair3
用途:对照验证 demo3 与官方管线。先停 demo3,再运行(同一设备独占):
```powershell
# tsdk_pair2:官方 ThermalSDK 同帧抓帧(gray/rgb/raw/ref/f20/tables/win
& build-artifacts\tsdk_pair2_fixed.exe C:\Project\MAG160C\analysis\pairs_xxx 12 6000
# tsdk_pair3:增强采集(+ 完整端点表/盲元记录/shutter/h1024/cdf/DDT 复制)
& build-artifacts\tsdk_pair3.exe C:\Project\MAG160C\analysis\pairs_xxx 8 6000
# 注意:config.txt 和 pair_*.meta/win 写在进程 CWD,跑完移回输出目录
```
参数:`<输出目录> <抓帧对数> <官方SDK初始化等待ms>`
若报 "no channel":停止所有程序后重新插拔 USB。
## 测试
```powershell
# 无硬件验证(纯计算)
build-artifacts\csdk_test_frame.exe
build-artifacts\csdk_test_temp.exe
build-artifacts\csdk_test_tcm.exe
build-artifacts\csdk_test_api.exe
build-artifacts\csdk_test_display.exe
```
## 协议要点(详见 analysis/protocol_spec.md
- 端点:EP0x03 命令 OUT / 0x82 响应 IN / 0x81 帧流 IN / 0x84 大块读 IN
- 命令 4 字节 `{magic}`,仅 FFC(0x6bb6b672) 用 8 字节 `{magic, param}`
- 帧:`0x1bb1b11b | counter | len | type(0/1) | ... | 像素 u16 LE | 0x1bb1b11c`
- 快门(设备温度代理)= 帧尾字 `frame[len+0x24]`width=160 时)
- 温度:`temp_mC = T2E[3*nuc - C]`C≈5797(会话相关)
## 文档索引
| 文档 | 内容 |
|---|---|
| `../analysis/protocol_spec.md` | USB 协议/帧/命令/温度完整规格 |
| `../analysis/reverse_20260813_full.md` | 官方管线 Ghidra 全量逆向 + 鬼影根因 |
| `../analysis/session_state.md` | 当前会话状态/恢复点(心跳)|
| `../交接_完整逆向工程说明_20260811.md` | 项目总交接(目录/环境/历史)|
| `WINDOWS_TESTING.md` | Windows 抓包与硬件测试指南 |
| `legacy/` | 历史工具源码归档(早期探索,功能已被现工具取代)|