/* ThermalSDK.dll harness: use the OFFICIAL high-level SDK directly. * Start() runs the whole vendor pipeline; we capture the rendered IR frame * via SetNewIRFrameDelegate and read temperatures. This gives the exact * ground truth of what the official app displays on this hardware. * * The IR frame callback delivers a 160x120x3 RGB image (official render). */ #define _WIN32_WINNT 0x0601 #include #include #include #include #include typedef void (CALLBACK *INewIRFrame)(const unsigned char *, int, int, int); typedef void (CALLBACK *INewDistance)(float); typedef void (CALLBACK *IDistanceError)(); typedef void (CALLBACK *INewLimitEvent)(bool); typedef void (CALLBACK *UpdateCallback)(bool, int); typedef bool (CALLBACK *fn_Start_t)(void); typedef void (CALLBACK *fn_Stop_t)(void); typedef bool (CALLBACK *fn_IsWorking_t)(void); typedef void (CALLBACK *fn_SetNewIRFrameDelegate_t)(INewIRFrame); typedef void (CALLBACK *fn_SetNewDistanceDelegate_t)(INewDistance); typedef void (CALLBACK *fn_SetDistanceError_t)(IDistanceError); typedef void (CALLBACK *fn_ReadTemperatureAtPoint_t)(int, int, unsigned char *); typedef void (CALLBACK *fn_SetTempBoundary_t)(double, double, double); typedef void (CALLBACK *fn_SetEmissivity_t)(double); typedef bool (CALLBACK *fn_Trigger_t)(void); typedef int (CALLBACK *fn_GetSDKVersion_t)(void); typedef void (CALLBACK *fn_SetUnitMode_t)(int); static HMODULE g_tsdk; static fn_Start_t T_Start; static fn_Stop_t T_Stop; static fn_IsWorking_t T_IsWorking; static fn_SetNewIRFrameDelegate_t T_SetNewIRFrameDelegate; static fn_SetNewDistanceDelegate_t T_SetNewDistanceDelegate; static fn_SetDistanceError_t T_SetDistanceError; static fn_ReadTemperatureAtPoint_t T_ReadTemperatureAtPoint; static fn_SetTempBoundary_t T_SetTempBoundary; static fn_SetEmissivity_t T_SetEmissivity; static fn_Trigger_t T_Trigger; static fn_GetSDKVersion_t T_GetSDKVersion; static fn_SetUnitMode_t T_SetUnitMode; static unsigned char g_rgb[160 * 120 * 3]; static volatile int g_frame_count; static void CALLBACK onIR(const unsigned char *buf, int w, int h, int ch) { if (buf && w == 160 && h == 120 && ch == 3 && g_frame_count < 10) { memcpy(g_rgb, buf, 160 * 120 * 3); g_frame_count++; printf(" IR frame %d: first px RGB=%d,%d,%d\n", g_frame_count, buf[0], buf[1], buf[2]); } else if (buf) { memcpy(g_rgb, buf, 160 * 120 * 3); g_frame_count++; } } static void CALLBACK onDist(float d) { (void)d; } static void CALLBACK onDistErr() {} int main(void) { const char *dir = "C:\\Project\\MAG160C\\IR_Camera_SDK-1.0.1\\windows\\windows\\app"; SetDllDirectoryA(dir); g_tsdk = LoadLibraryA("ThermalSDK.dll"); if (!g_tsdk) { printf("ThermalSDK load failed %lu\n", GetLastError()); return 1; } T_Start = (fn_Start_t)GetProcAddress(g_tsdk, "Start"); T_Stop = (fn_Stop_t)GetProcAddress(g_tsdk, "Stop"); T_IsWorking = (fn_IsWorking_t)GetProcAddress(g_tsdk, "IsWorking"); T_SetNewIRFrameDelegate = (fn_SetNewIRFrameDelegate_t)GetProcAddress(g_tsdk, "SetNewIRFrameDelegate"); T_SetNewDistanceDelegate = (fn_SetNewDistanceDelegate_t)GetProcAddress(g_tsdk, "SetNewDistanceDelegate"); T_SetDistanceError = (fn_SetDistanceError_t)GetProcAddress(g_tsdk, "SetDistanceError"); T_ReadTemperatureAtPoint = (fn_ReadTemperatureAtPoint_t)GetProcAddress(g_tsdk, "ReadTemperatureAtPoint"); T_SetTempBoundary = (fn_SetTempBoundary_t)GetProcAddress(g_tsdk, "SetTempBoundary"); T_SetEmissivity = (fn_SetEmissivity_t)GetProcAddress(g_tsdk, "SetEmissivity"); T_Trigger = (fn_Trigger_t)GetProcAddress(g_tsdk, "Trigger"); T_GetSDKVersion = (fn_GetSDKVersion_t)GetProcAddress(g_tsdk, "GetSDKVersion"); T_SetUnitMode = (fn_SetUnitMode_t)GetProcAddress(g_tsdk, "SetUnitMode"); if (!T_Start || !T_SetNewIRFrameDelegate) { printf("missing exports\n"); return 2; } printf("ThermalSDK version: %d\n", T_GetSDKVersion ? T_GetSDKVersion() : -1); T_SetUnitMode(0); /* metric */ T_SetTempBoundary(30.0, 44.0, 37.0); T_SetEmissivity(0.98); T_SetNewDistanceDelegate(onDist); T_SetDistanceError(onDistErr); T_SetNewIRFrameDelegate(onIR); printf("Start() ...\n"); bool ok = T_Start(); printf("Start -> %d\n", ok); /* wait for frames */ DWORD t0 = GetTickCount(); while (g_frame_count < 30 && GetTickCount() - t0 < 20000) Sleep(100); printf("received %d IR frames in %.1fs\n", g_frame_count, (GetTickCount() - t0) / 1000.0); /* temperature probe at center */ unsigned char res[64] = {0}; T_ReadTemperatureAtPoint(80, 60, res); printf("center temp result bytes: "); for (int i = 0; i < 32; ++i) printf("%02x ", res[i]); printf("\n"); double *d = (double *)(res + 8); printf(" raw=%.4f arm=%.4f (guessed layout)\n", d[0], d[1]); /* save official render */ if (g_frame_count > 0) { unsigned sz = 54 + 160 * 120 * 3; unsigned char hdr[54] = {0}; hdr[0] = 'B'; hdr[1] = 'M'; hdr[2] = sz; hdr[3] = sz >> 8; hdr[4] = sz >> 16; hdr[5] = sz >> 24; hdr[10] = 54; hdr[14] = 40; hdr[18] = 160; hdr[22] = 120; hdr[26] = 1; hdr[28] = 24; FILE *f = fopen("official_render.bmp", "wb"); if (f) { fwrite(hdr, 1, 54, f); fwrite(g_rgb, 1, 160 * 120 * 3, f); fclose(f); printf("saved official_render.bmp\n"); } /* also save raw RGB dump */ f = fopen("official_render.rgb", "wb"); if (f) { fwrite(g_rgb, 1, 160 * 120 * 3, f); fclose(f); } } T_Stop(); printf("done\n"); return 0; }