Files
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

149 lines
5.5 KiB
C

/* MAG160C headless FFC cadence test - replicates the official demo FFC
* timing from analysis/captures/libusb0_trace.txt:
* init: 66b 66c 66f -> FFC(0) -> START
* FFC(1) after ~10th complete frame (switch stream to type=0)
* then every FFC_PERIOD frames: FFC(0), and FFC_GAP frames later FFC(1)
* Target: type=0 stream keeps flowing for 1000+ frames without stalling.
* Prints per-second progress; exits with 0 on success.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <windows.h>
#include <libusb.h>
#define FFC_PERIOD 400
#define FFC_GAP 9
#define WANT_FRAMES 1400
static libusb_context *g_ctx;
static libusb_device_handle *g_h;
static int sendcmd(unsigned magic, unsigned param, int len) {
unsigned char cmd[8] = {0};
cmd[0] = (unsigned char)(magic);
cmd[1] = (unsigned char)(magic >> 8);
cmd[2] = (unsigned char)(magic >> 16);
cmd[3] = (unsigned char)(magic >> 24);
if (len >= 8) {
cmd[4] = (unsigned char)(param);
cmd[5] = (unsigned char)(param >> 8);
cmd[6] = (unsigned char)(param >> 16);
cmd[7] = (unsigned char)(param >> 24);
}
int xfer = 0;
if (libusb_bulk_transfer(g_h, 0x03, cmd, len, &xfer, 2000)) return -1;
unsigned char resp[0x1000];
if (libusb_bulk_transfer(g_h, 0x82, resp, sizeof(resp), &xfer, 2000)) return -1;
return 0;
}
int main(void) {
printf("MAG160C FFC cadence test (want %d frames)\n", WANT_FRAMES);
if (libusb_init(&g_ctx)) { printf("libusb_init failed\n"); return 1; }
libusb_device **list = NULL;
ssize_t cnt = libusb_get_device_list(g_ctx, &list);
for (ssize_t i = 0; i < cnt && !g_h; ++i) {
struct libusb_device_descriptor d;
libusb_get_device_descriptor(list[i], &d);
if (d.idVendor == 0x833c) libusb_open(list[i], &g_h);
}
libusb_free_device_list(list, 1);
if (!g_h) { printf("no device\n"); libusb_exit(g_ctx); return 1; }
libusb_set_configuration(g_h, 2);
libusb_set_configuration(g_h, 1);
if (libusb_claim_interface(g_h, 0)) { printf("claim failed\n"); return 1; }
if (sendcmd(0x6bb6b66b, 0, 4)) { printf("66b failed\n"); return 1; }
if (sendcmd(0x6bb6b66c, 0, 4)) { printf("66c failed\n"); return 1; }
if (sendcmd(0x6bb6b66f, 0, 4)) { printf("66f failed\n"); return 1; }
if (sendcmd(0x6bb6b672, 0, 8)) { printf("FFC(0) pre failed\n"); return 1; }
Sleep(100);
if (sendcmd(0x6bb6b672, 0, 8)) { printf("FFC(0) pre2 failed\n"); return 1; }
Sleep(300);
if (sendcmd(0x6bb6b673, 0, 4)) { printf("START failed\n"); return 1; }
Sleep(700);
unsigned char frame[40000];
unsigned prev = 0xffffffff;
int nread = 0, n0 = 0, n1 = 0;
int ffc_started = 0, ffc_cycle = 0, ffc_wait1 = 0;
int stall_wakes = 0;
DWORD t_start = GetTickCount();
DWORD last_frame = t_start, last_wake = t_start;
DWORD last_report = t_start;
while (n0 < WANT_FRAMES) {
unsigned char hdr[64];
int xfer = 0;
if (libusb_bulk_transfer(g_h, 0x81, hdr, sizeof(hdr), &xfer, 200) && xfer < 28) {
DWORD now = GetTickCount();
if (now - last_frame > 3000 && now - last_wake > 5000) {
sendcmd(0x6bb6b672, 1, 8);
last_wake = now;
stall_wakes++;
printf(" [stall watchdog] FFC(1) sent (%d)\n", stall_wakes);
}
continue;
}
if (xfer < 28) continue;
unsigned m = (unsigned)hdr[0] | ((unsigned)hdr[1] << 8) |
((unsigned)hdr[2] << 16) | ((unsigned)hdr[3] << 24);
if (m != 0x1bb1b11b) continue;
unsigned c = (unsigned)hdr[4] | ((unsigned)hdr[5] << 8) |
((unsigned)hdr[6] << 16) | ((unsigned)hdr[7] << 24);
if (c == prev) continue;
prev = c;
if (libusb_bulk_transfer(g_h, 0x81, frame, sizeof(frame), &xfer, 200) ||
xfer < 38400) {
continue;
}
unsigned type = (unsigned)hdr[12];
nread++;
last_frame = GetTickCount();
if (type == 0) n0++; else n1++;
if (!ffc_started && nread == 10) {
sendcmd(0x6bb6b672, 1, 8);
ffc_started = 1;
ffc_cycle = 0;
printf(" frame 10: FFC(1) sent -> type=0 mode\n");
continue;
}
if (ffc_started) {
ffc_cycle++;
if (ffc_wait1 && ffc_cycle >= FFC_GAP) {
sendcmd(0x6bb6b672, 1, 8);
ffc_wait1 = 0;
ffc_cycle = 0;
} else if (!ffc_wait1 && ffc_cycle >= FFC_PERIOD) {
sendcmd(0x6bb6b672, 0, 8);
ffc_wait1 = 1;
ffc_cycle = 0;
}
}
DWORD now = GetTickCount();
if (now - last_report >= 5000) {
double secs = (now - t_start) / 1000.0;
printf(" t=%6.1fs frames=%d (type0=%d type1=%d) fps=%.1f\n",
secs, nread, n0, n1, n0 / secs);
last_report = now;
}
}
DWORD t_end = GetTickCount();
double secs = (t_end - t_start) / 1000.0;
printf("\nDONE: %d frames in %.1fs (fps=%.1f) type0=%d type1=%d stall_wakes=%d\n",
nread, secs, nread / secs, n0, n1, stall_wakes);
int pass = (n0 >= 1000) ? 1 : 0;
printf("%s\n", pass ? "PASS: type=0 stream >= 1000 frames" :
"FAIL: type=0 stream < 1000 frames");
Sleep(300);
libusb_clear_halt(g_h, 0x03);
libusb_clear_halt(g_h, 0x82);
sendcmd(0x6bb6b674, 0, 4);
libusb_close(g_h);
libusb_exit(g_ctx);
return pass ? 0 : 2;
}