- 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 移植章节
288 lines
12 KiB
Markdown
288 lines
12 KiB
Markdown
# MAG160C C SDK (csdk/)
|
||
|
||
MAG160C 热像仪(160×120,USB 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 CLI:ir-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 导入库)。
|
||
|
||
### 方式 B:CMake(有 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] 小端 uint16,160×120 */
|
||
}
|
||
|
||
int main(void) {
|
||
mag160c_ctx_t *ctx = NULL;
|
||
mag160c_ir_t *ir = NULL;
|
||
mag160c_init(&ctx);
|
||
mag160c_ir_open(ctx, &ir); /* 自动找 VID 0x833c,config 2,interface 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)` | 手动 FFC(0 或 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 ...
|
||
```
|
||
|
||
说明:
|
||
- 0x17770(auto gray 双边滤波)的空间权重表在官方二进制 .data 节被裁剪
|
||
无法提取,demo3 用标准高斯核近似(σ=2.0),值域核按官方生成式(sqrt 核)。
|
||
- 0x17c40(manual)已逐行翻译: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(界面/交互动画)+ rlottie(Lottie 特效),参考
|
||
LiThermal 项目;主控建议全志 T113-S3(QFP128,非 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/` | 历史工具源码归档(早期探索,功能已被现工具取代)|
|