Files
MAG160C/csdk/tools/tsdk_pair3.c
T
ZXCLI 0bfb926892 完成官方管线全量逆向与 demo3 v5 复刻,清理仓库
- 逆向:Ghidra/IDA 全量反编译 CoreSDKLib.dll/ThermalSDK.dll/libthermalSDK.so/
  libcoresdk.so(ARM64)/libmagcore.so,导出 analysis/ida/export/
- 解码官方渲染管线:DDT 校准表加载->快门端点选择->Q12 插值->ref(4x type1 帧
  均值)->NUC 查表->盲元补偿->窗口->LUT1024 重建->2x 升采样->调色板
- 逐像素验证:NUC+盲元 0/19200、插值 0 误差、2x 0/76800、窗口一致
- demo3 v5:完整复刻官方管线(含 DDT 解析、FFC 状态机、快门温度驱动),
  修复 load_ddt 表错位导致的零像素问题
- 鬼影根因分析写入 analysis/reverse_20260813_full.md
- 心跳/恢复机制:analysis/session_state.md + tools/resume_rev.ps1
- 新增 tsdk_pair3 增强采集工具;历史工具归档 csdk/tools/legacy/;
  根目录抓帧残留删除,历史文档归档 analysis/history/
- csdk/README.md 完整使用文档;.gitignore/.gitattributes 补 LFS 规则
2026-08-13 23:16:12 +08:00

317 lines
16 KiB
C

/* tsdk_pair3: same-frame capture of official pipeline outputs + full NUC/
* window/ref state, for replicating CoreSDKLib.dll in the C SDK.
* Extends tsdk_pair2 with:
* - per-frame shutter (metadata+0x2c), frame counters
* - config dump: 0x24, 0x48, 0x4c, 0x54/0x58/0x5c/0x60, 0x47944..0x47954,
* 0x11c, DDT header fields (0x41340..0x41880), endpoint arrays
* - DDT file copy (path from dev+0x4134c)
* - stats (0x42010..0x42024) + window (0x4202c/0x42030) + LUT1024 + hist
*/
#define _WIN32_WINNT 0x0601
#include <windows.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
typedef void (CALLBACK *INewIRFrame)(const unsigned char *, int, int, int);
typedef bool (CALLBACK *fn_Start_t)(void);
typedef void (CALLBACK *fn_Stop_t)(void);
typedef void (CALLBACK *fn_SetNewIRFrameDelegate_t)(INewIRFrame);
typedef void (CALLBACK *fn_SetTempBoundary_t)(double, double, double);
typedef void (CALLBACK *fn_SetUnitMode_t)(int);
typedef void (CALLBACK *fn_ReadTemperatureAtPoint_t)(int, int, unsigned char *);
typedef int (CALLBACK *MAG_GetOutputBMPdata_t)(int, unsigned char **, void **);
typedef int (CALLBACK *MAG_GetOutputBMPdataRGB24_t)(int, unsigned char *, int, int);
typedef int (CALLBACK *MAG_GetTemperatureData_Raw_t)(int, unsigned int *, int, int);
typedef int (CALLBACK *MAG_GetOutputColorBardata_t)(int, void **, void **);
typedef int (CALLBACK *MAG_TriggerFFC_t)(int, int);
static volatile int g_frames;
static unsigned char g_cb[320 * 240 * 3];
static int g_cbw, g_cbh;
static const char *g_dir = ".";
static void CALLBACK onIR(const unsigned char *buf, int w, int h, int ch) {
if (buf && w > 0 && h > 0 && ch == 3) {
memcpy(g_cb, buf, (size_t)w * h * ch);
g_cbw = w; g_cbh = h;
}
g_frames++;
}
static void save(const char *name, const void *buf, size_t n) {
char path[512];
snprintf(path, sizeof(path), "%s\\%s", g_dir, name);
FILE *f = fopen(path, "wb");
if (f) { fwrite(buf, 1, n, f); fclose(f); }
}
static int is_ro_ptr(const void *p, size_t n) {
if (!p) return 0;
MEMORY_BASIC_INFORMATION mi;
if (VirtualQuery(p, &mi, sizeof(mi)) == 0) return 0;
if (mi.State != MEM_COMMIT) return 0;
if (mi.Protect == PAGE_NOACCESS) return 0;
if ((size_t)((const char *)p - (const char *)mi.BaseAddress) + n > mi.RegionSize)
return 0;
return 1;
}
int main(int argc, char **argv) {
int npairs = 24;
int start_delay = 6000;
double tb[3] = {30.0, 44.0, 37.0};
if (argc > 1) g_dir = argv[1];
if (argc > 2) npairs = atoi(argv[2]);
if (argc > 3) start_delay = atoi(argv[3]);
if (argc > 4) tb[0] = atof(argv[4]);
if (argc > 5) tb[1] = atof(argv[5]);
if (argc > 6) tb[2] = atof(argv[6]);
SetDllDirectoryA("C:\\Project\\MAG160C\\IR_Camera_SDK-1.0.1\\windows\\windows\\app");
HMODULE t = LoadLibraryA("ThermalSDK.dll");
HMODULE c = LoadLibraryA("CoreSDKLib.dll");
printf("T=%p C=%p\n", (void*)t, (void*)c);
if (!t || !c) return 1;
fn_Start_t T_Start = (fn_Start_t)GetProcAddress(t, "Start");
fn_Stop_t T_Stop = (fn_Stop_t)GetProcAddress(t, "Stop");
fn_SetNewIRFrameDelegate_t T_Set = (fn_SetNewIRFrameDelegate_t)GetProcAddress(t, "SetNewIRFrameDelegate");
fn_SetTempBoundary_t T_Bound = (fn_SetTempBoundary_t)GetProcAddress(t, "SetTempBoundary");
fn_SetUnitMode_t T_Unit = (fn_SetUnitMode_t)GetProcAddress(t, "SetUnitMode");
fn_ReadTemperatureAtPoint_t T_Temp = (fn_ReadTemperatureAtPoint_t)GetProcAddress(t, "ReadTemperatureAtPoint");
MAG_GetOutputBMPdata_t G_Gray = (MAG_GetOutputBMPdata_t)GetProcAddress(c, "MAG_GetOutputBMPdata");
MAG_GetOutputBMPdataRGB24_t G_RGB = (MAG_GetOutputBMPdataRGB24_t)GetProcAddress(c, "MAG_GetOutputBMPdataRGB24");
MAG_GetTemperatureData_Raw_t G_TempRaw = (MAG_GetTemperatureData_Raw_t)GetProcAddress(c, "MAG_GetTemperatureData_Raw");
MAG_GetOutputColorBardata_t G_Bar = (MAG_GetOutputColorBardata_t)GetProcAddress(c, "MAG_GetOutputColorBardata");
if (!T_Start || !T_Set || !G_Gray || !G_RGB) { printf("missing export\n"); return 2; }
if (T_Unit) T_Unit(0);
if (T_Bound) T_Bound(tb[0], tb[1], tb[2]);
T_Set(onIR);
printf("Start()...\n"); fflush(stdout);
BOOL ok = T_Start();
printf("Start=%d\n", ok); fflush(stdout);
printf("warming %d ms...\n", start_delay); fflush(stdout);
Sleep(start_delay);
unsigned char *gray = NULL;
void *hdr = NULL;
int chan = -1;
for (int i = 0; i < 8; ++i) {
int rc = G_Gray(i, &gray, &hdr);
printf("chan %d: rc=%d gray=%p hdr=%p\n", i, rc, (void*)gray, (void*)hdr);
if (rc && gray && hdr) { chan = i; break; }
}
if (chan < 0) { printf("no channel\n"); T_Stop(); return 3; }
unsigned char *dev = (unsigned char *)hdr - 0xaf0;
int w = *(int *)(dev + 0xaf4);
int h = *(int *)(dev + 0xaf8);
int n = w * h;
int nw = w / 2, nh = h / 2;
int nn = nw * nh;
printf("dev=%p w=%d h=%d\n", (void*)dev, w, h);
/* ---- config dump ---- */
FILE *cfg = fopen("config.txt", "w");
if (cfg) {
fprintf(cfg, "dev24=%d dev48=%d dev4c=%d dev54=%d dev58=%d dev5c=%d dev60=%d\n",
*(int *)(dev + 0x24), *(int *)(dev + 0x48), *(int *)(dev + 0x4c),
*(int *)(dev + 0x54), *(int *)(dev + 0x58), *(int *)(dev + 0x5c),
*(int *)(dev + 0x60));
fprintf(cfg, "11c=%d 41340=%d 41344=%d 41348=%d 4134c=%ls\n",
*(int *)(dev + 0x11c), *(int *)(dev + 0x41340), *(int *)(dev + 0x41344),
*(int *)(dev + 0x41348), (wchar_t *)(dev + 0x4134c));
fprintf(cfg, "41558=%d 41554=%d 4155c=%d 41560=%d 47944=%d 47948=%d 4794c=%d 47950=%d 47954=%d 47938=%d\n",
*(int *)(dev + 0x41558), *(int *)(dev + 0x41554), *(int *)(dev + 0x4155c),
*(int *)(dev + 0x41560), *(int *)(dev + 0x47944), *(int *)(dev + 0x47948),
*(int *)(dev + 0x4794c), *(int *)(dev + 0x47950), *(int *)(dev + 0x47954),
*(int *)(dev + 0x47938));
int cnt = *(int *)(dev + 0x41558);
if (cnt < 1 || cnt > 64) cnt = 1;
fprintf(cfg, "T:");
for (int i = 0; i < cnt; ++i) fprintf(cfg, " %d", *(int *)(dev + 0x41564 + i * 4));
fprintf(cfg, "\nB:");
for (int i = 0; i < cnt; ++i) fprintf(cfg, " %d", *(int *)(dev + 0x415b4 + i * 4));
fprintf(cfg, "\nC:");
for (int i = 0; i < cnt; ++i) fprintf(cfg, " %d", *(int *)(dev + 0x41604 + i * 4));
fprintf(cfg, "\nD(blind cnt):");
for (int i = 0; i < cnt - 1; ++i) fprintf(cfg, " %d", *(int *)(dev + 0x41654 + i * 4));
fprintf(cfg, "\nloaded:");
for (int i = 0; i < cnt; ++i) fprintf(cfg, " %d", *(int *)(dev + 0x416b8 + i * 4));
fprintf(cfg, "\noffsets(41708):");
for (int i = 0; i < cnt; ++i) fprintf(cfg, " %d", *(int *)(dev + 0x41708 + i * 4));
fprintf(cfg, "\nthr_off(41758):");
for (int i = 0; i < cnt; ++i) fprintf(cfg, " %d", *(int *)(dev + 0x41758 + i * 4));
fprintf(cfg, "\nblind_off(417a8):");
for (int i = 0; i < cnt; ++i) fprintf(cfg, " %d", *(int *)(dev + 0x417a8 + i * 4));
fprintf(cfg, "\nblind_off2(417f4):");
for (int i = 0; i < cnt; ++i) fprintf(cfg, " %d", *(int *)(dev + 0x417f4 + i * 4));
fprintf(cfg, "\nbases: 416a0=%p 416a8=%p 416b0=%p\n",
*(void **)(dev + 0x416a0), *(void **)(dev + 0x416a8), *(void **)(dev + 0x416b0));
fprintf(cfg, "41840=%d 41848=%p 41850=%p 41858=%p 41860=%p 41868=%p 41870=%p 41878=%p\n",
*(int *)(dev + 0x41840), *(void **)(dev + 0x41848), *(void **)(dev + 0x41850),
*(void **)(dev + 0x41858), *(void **)(dev + 0x41860), *(void **)(dev + 0x41868),
*(void **)(dev + 0x41870), *(void **)(dev + 0x41878));
fprintf(cfg, "41f0c=%d 41f3c=%d 41fdc=%d 41fe0=%d 41fe4=%d 41fe8=%d\n",
*(int *)(dev + 0x41f0c), *(int *)(dev + 0x41f3c), *(int *)(dev + 0x41fdc),
*(int *)(dev + 0x41fe0), *(int *)(dev + 0x41fe4), *(int *)(dev + 0x41fe8));
fprintf(cfg, "2d47=%d 2d86=%d 2d78=%d 2d88=%d 2d8c=%d 2d90=%d 2d94=%d 2d98=%d 2d9c=%d\n",
*(char *)(dev + 0x2d47), *(short *)(dev + 0x2d86),
*(int *)(dev + 0x2d78), *(int *)(dev + 0x2d88), *(int *)(dev + 0x2d8c),
*(int *)(dev + 0x2d90), *(int *)(dev + 0x2d94), *(int *)(dev + 0x2d98),
*(int *)(dev + 0x2d9c));
fprintf(cfg, "47940=%d 44c50=%d 44c60=%d 44c64=%d 44c68=%d 42010=%d 42014=%d\n",
*(int *)(dev + 0x47940), *(int *)(dev + 0x44c50), *(int *)(dev + 0x44c60),
*(int *)(dev + 0x44c64), *(int *)(dev + 0x44c68),
*(int *)(dev + 0x42010), *(int *)(dev + 0x42014));
fclose(cfg);
}
/* copy the DDT file */
wchar_t *ddtp = (wchar_t *)(dev + 0x4134c);
if (ddtp && *ddtp) {
printf("DDT path: %ls\n", ddtp); fflush(stdout);
char apath[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, ddtp, -1, apath, MAX_PATH, NULL, NULL);
FILE *sf = fopen(apath, "rb");
if (sf) {
fseek(sf, 0, SEEK_END);
long sz = ftell(sf);
fseek(sf, 0, SEEK_SET);
void *buf = malloc(sz);
if (buf) {
fread(buf, 1, sz, sf);
save("official.ddt", buf, sz);
printf("DDT copied: %ld bytes\n", sz);
free(buf);
}
fclose(sf);
} else printf("DDT file not readable: %s\n", apath);
} else printf("no DDT path\n");
fflush(stdout);
unsigned char *rgb = malloc((size_t)n * 3);
unsigned short *raw = malloc((size_t)nn * 2);
unsigned char *pal = malloc(256 * 4);
unsigned int *t32 = malloc((size_t)n * 4);
unsigned char *g2 = malloc((size_t)n);
MAG_TriggerFFC_t G_FFC = (MAG_TriggerFFC_t)GetProcAddress(c, "MAG_TriggerFFC");
int prev = g_frames;
for (int k = 0; k < npairs; ++k) {
if (G_FFC && k == npairs / 3) { G_FFC(chan, 1); Sleep(1500); prev = g_frames; }
if (G_FFC && k == 2 * npairs / 3) { G_FFC(chan, 0); Sleep(1500); prev = g_frames; }
int t0 = GetTickCount();
while (g_frames == prev && GetTickCount() - t0 < 3000) Sleep(5);
prev = g_frames;
Sleep(2);
memcpy(g2, gray, (size_t)n);
int rcr = G_RGB(chan, rgb, n * 3, 1);
unsigned short *rawp = *(unsigned short **)(dev + 0x270);
memcpy(raw, rawp, (size_t)nn * 2);
memcpy(pal, dev + 0xb18, 256 * 4);
int rct = G_TempRaw ? G_TempRaw(chan, t32, nn * 4, 1) : 0;
char base[64];
snprintf(base, sizeof(base), "pair_%03d", k);
char nm[128];
snprintf(nm, sizeof(nm), "%s.gray", base); save(nm, g2, (size_t)n);
snprintf(nm, sizeof(nm), "%s.rgb", base); save(nm, rgb, (size_t)n * 3);
snprintf(nm, sizeof(nm), "%s.raw", base); save(nm, raw, (size_t)nn * 2);
snprintf(nm, sizeof(nm), "%s.pal", base); save(nm, pal, 256 * 4);
snprintf(nm, sizeof(nm), "%s.cbrgb", base); save(nm, g_cb, (size_t)g_cbw * g_cbh * 3);
if (rct) { snprintf(nm, sizeof(nm), "%s.t32", base); save(nm, t32, (size_t)nn * 4); }
/* frame metadata + shutter: the frame buffer base at dev+0x50 */
unsigned char *fb = *(unsigned char **)(dev + 0x50);
if (!is_ro_ptr(fb, 0x4c + 38400 + 8)) fb = NULL;
unsigned int fcnt = *(unsigned int *)(dev + 8);
unsigned int shutter = fb ? *(unsigned int *)(fb + 0x2c) : 0;
unsigned int shutter2 = fb ? *(unsigned int *)(fb + 0x28) : 0;
unsigned int ftype = fb ? *(unsigned int *)(fb + 0x40) : 0;
unsigned int dev54 = *(unsigned int *)(dev + 0x54);
unsigned int dev5c = *(unsigned int *)(dev + 0x5c);
unsigned int dev60 = *(unsigned int *)(dev + 0x60);
unsigned int win_hi = *(unsigned int *)(dev + 0x4202c);
unsigned int win_lo = *(unsigned int *)(dev + 0x42030);
unsigned int s_max = *(unsigned int *)(dev + 0x42010);
unsigned int s_min = *(unsigned int *)(dev + 0x42014);
unsigned int s_mean = *(unsigned int *)(dev + 0x42018);
unsigned int s_std = *(unsigned int *)(dev + 0x4201c);
unsigned int sel = *(unsigned int *)(dev + 0x41840);
snprintf(nm, sizeof(nm), "%s.meta", base);
{
unsigned int v[16] = {fcnt, shutter, shutter2, ftype, dev54, dev5c, dev60,
win_hi, win_lo, s_max, s_min, s_mean, s_std, sel,
*(unsigned int *)(dev + 0x41558), *(unsigned int *)(dev + 0x41554)};
FILE *f = fopen(nm, "wb");
if (f) { fwrite(v, 4, 16, f); fclose(f); }
}
/* window + stats + lut + hist */
snprintf(nm, sizeof(nm), "%s.win", base);
{
FILE *f = fopen(nm, "wb");
if (f) {
unsigned int v[8] = {win_hi, win_lo, s_max, s_min, s_mean, s_std,
*(unsigned int *)(dev + 0x42020), *(unsigned int *)(dev + 0x42024)};
fwrite(v, 4, 8, f); fclose(f);
}
}
snprintf(nm, sizeof(nm), "%s.lut", base); save(nm, dev + 0x4284c, 1024);
snprintf(nm, sizeof(nm), "%s.hist", base); save(nm, dev + 0x4204c, 256 * 4);
snprintf(nm, sizeof(nm), "%s.h1024", base); save(nm, dev + 0x42c4c, 1024 * 4);
snprintf(nm, sizeof(nm), "%s.cdf", base); save(nm, dev + 0x43c4c, 1024 * 4);
/* ref + f20 */
unsigned short *refp = *(unsigned short **)(dev + 0x41ef0);
if (is_ro_ptr(refp, (size_t)nn * 2)) { snprintf(nm, sizeof(nm), "%s.ref", base); save(nm, refp, (size_t)nn * 2); }
void *f20 = *(void **)(dev + 0x41f20);
if (is_ro_ptr(f20, (size_t)nn * 2)) { snprintf(nm, sizeof(nm), "%s.f20", base); save(nm, f20, (size_t)nn * 2); }
/* full working tables + endpoints (sel/sel+1) */
{
int nsegs = *(int *)(dev + 0x41554);
int c5c = *(int *)(dev + 0x4155c);
size_t thr_sz = (size_t)(nsegs - 1) * nn * 2 + (size_t)c5c;
size_t g_sz = (size_t)nsegs * nn * 4;
void *p;
p = *(void **)(dev + 0x41848); if (is_ro_ptr(p, thr_sz)) { snprintf(nm, sizeof(nm), "%s.thr0", base); save(nm, p, thr_sz); }
p = *(void **)(dev + 0x41850); if (is_ro_ptr(p, thr_sz)) { snprintf(nm, sizeof(nm), "%s.thr1", base); save(nm, p, thr_sz); }
p = *(void **)(dev + 0x41858); if (is_ro_ptr(p, (size_t)(nsegs - 1) * nn * 2)) { snprintf(nm, sizeof(nm), "%s.thrw", base); save(nm, p, (size_t)(nsegs - 1) * nn * 2); }
p = *(void **)(dev + 0x41860); if (is_ro_ptr(p, g_sz)) { snprintf(nm, sizeof(nm), "%s.g0", base); save(nm, p, g_sz); }
p = *(void **)(dev + 0x41868); if (is_ro_ptr(p, g_sz)) { snprintf(nm, sizeof(nm), "%s.g1", base); save(nm, p, g_sz); }
p = *(void **)(dev + 0x41870); if (is_ro_ptr(p, g_sz)) { snprintf(nm, sizeof(nm), "%s.gw", base); save(nm, p, g_sz); }
p = *(void **)(dev + 0x41878); if (is_ro_ptr(p, 0x1000)) {
int sel2 = *(int *)(dev + 0x41840);
int bc = sel2 >= 0 && sel2 < 64 ? *(int *)(dev + 0x41654 + (size_t)sel2 * 4) : 0;
if (bc > 0 && bc < 100000 && is_ro_ptr(p, (size_t)bc * 40)) {
snprintf(nm, sizeof(nm), "%s.blind", base);
save(nm, p, (size_t)bc * 40);
printf(" blind records: %d\n", bc);
}
}
}
/* frame header bytes + tail (raw USB frame, from the parser buffer) */
{
unsigned char *rb = *(unsigned char **)(dev + 0x2d20);
if (is_ro_ptr(rb, 0x1c + 0x9600 + 0x100)) {
snprintf(nm, sizeof(nm), "%s.fhdr", base);
save(nm, rb, 0x40);
snprintf(nm, sizeof(nm), "%s.ftail", base);
save(nm, rb + 0x1c + 0x9600, 0x100);
}
}
printf("[%d] fcnt=%u shutter=%u/%u type=%u dev54=%u dev5c=%u dev60=%u sel=%u win=[%u,%u] stats=(%u..%u m%u s%u)\n",
k, fcnt, shutter, shutter2, ftype, dev54, dev5c, dev60, sel,
win_hi, win_lo, s_max, s_min, s_mean, s_std);
fflush(stdout);
Sleep(100);
}
T_Stop();
printf("done\n");
return 0;
}