- 逆向: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 规则
317 lines
16 KiB
C
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;
|
|
}
|