/* Capture type=0 frames and dump spatial/temporal statistics to reveal * fixed-pattern noise (mura), bad pixels, and startup-vs-settled behavior. * Writes per-pixel mean over N frames + frame-level row/col profiles. */ #include #include #include #include #include #define W 160 #define H 120 #define NPIX (W * H) 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; } /* return 1 on a valid type=0 frame */ static int read_frame(unsigned char *frame, unsigned *type) { unsigned char hdr[64]; static unsigned prev = 0xffffffff; int xfer = 0; if (libusb_bulk_transfer(g_h, 0x81, hdr, sizeof(hdr), &xfer, 200) && xfer < 28) return 0; if (xfer < 28) return 0; unsigned m = (unsigned)hdr[0] | ((unsigned)hdr[1] << 8) | ((unsigned)hdr[2] << 16) | ((unsigned)hdr[3] << 24); if (m != 0x1bb1b11b) return 0; unsigned c = (unsigned)hdr[4] | ((unsigned)hdr[5] << 8) | ((unsigned)hdr[6] << 16) | ((unsigned)hdr[7] << 24); if (c == prev) return 0; prev = c; if (libusb_bulk_transfer(g_h, 0x81, frame, 40000, &xfer, 200) || xfer < 38400) return 0; *type = (unsigned)hdr[12]; return 1; } int main(int argc, char **argv) { int nframes = argc > 1 ? atoi(argv[1]) : 200; const char *out = argc > 2 ? argv[2] : "frame_stats.txt"; if (libusb_init(&g_ctx)) 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"); return 1; } libusb_set_configuration(g_h, 2); libusb_set_configuration(g_h, 1); if (libusb_claim_interface(g_h, 0)) return 1; sendcmd(0x6bb6b66b, 0, 4); sendcmd(0x6bb6b66c, 0, 4); sendcmd(0x6bb6b66f, 0, 4); sendcmd(0x6bb6b672, 0, 8); Sleep(100); sendcmd(0x6bb6b672, 0, 8); Sleep(300); sendcmd(0x6bb6b673, 0, 4); Sleep(700); unsigned char frame[40000]; unsigned type = 1; /* drain + FFC(1) after ~10 complete frames switches the stream to * type=0 (verified cadence) */ int drained = 0; for (int i = 0; i < 120; ++i) { if (!read_frame(frame, &type)) { Sleep(10); continue; } drained++; if (drained == 10) { sendcmd(0x6bb6b672, 1, 8); Sleep(200); } if (type == 0) break; } if (type != 0) { printf("failed to reach type=0 stream\n"); return 3; } double mean[NPIX]; memset(mean, 0, sizeof(mean)); double row[H], col[W]; memset(row, 0, sizeof(row)); memset(col, 0, sizeof(col)); unsigned short last[NPIX]; double delta_sum = 0; int delta_n = 0; int got = 0, type0 = 0, type1 = 0; FILE *f = fopen(out, "w"); if (!f) return 2; for (int n = 0; n < nframes; ++n) { if (!read_frame(frame, &type)) { Sleep(10); n--; continue; } got++; if (type) { type1++; continue; } type0++; /* frame stats */ long fr_sum = 0; unsigned fr_min = 65535, fr_max = 0; for (int i = 0; i < NPIX; ++i) { unsigned v = (unsigned)frame[i * 2 + 28] | ((unsigned)frame[i * 2 + 29] << 8); mean[i] += v; fr_sum += v; if (v < fr_min) fr_min = v; if (v > fr_max) fr_max = v; if (got > 1) { int d = (int)v - (int)last[i]; if (d < 0) d = -d; delta_sum += d; delta_n++; } last[i] = (unsigned short)v; } fprintf(f, "FRAME %d type0 mean=%.0f min=%u max=%u meandelta=%.1f\n", n, (double)fr_sum / NPIX, fr_min, fr_max, delta_n ? delta_sum / delta_n : 0); delta_sum = 0; delta_n = 0; } for (int i = 0; i < NPIX; ++i) mean[i] /= type0 ? type0 : 1; for (int y = 0; y < H; ++y) { double s = 0; for (int x = 0; x < W; ++x) s += mean[y * W + x]; row[y] = s / W; } for (int x = 0; x < W; ++x) { double s = 0; for (int y = 0; y < H; ++y) s += mean[y * W + x]; col[x] = s / H; } /* per-pixel deviation from row+col model (mura detection) */ fprintf(f, "\nROW_PROFILE:\n"); for (int y = 0; y < H; ++y) fprintf(f, "%d %.1f\n", y, row[y]); fprintf(f, "\nCOL_PROFILE:\n"); for (int x = 0; x < W; ++x) fprintf(f, "%d %.1f\n", x, col[x]); fprintf(f, "\nPIXEL_DEVIATION (mean - row - col + global):\n"); double gm = 0; for (int i = 0; i < NPIX; ++i) gm += mean[i]; gm /= NPIX; for (int y = 0; y < H; ++y) { for (int x = 0; x < W; ++x) { double dev = mean[y * W + x] - row[y] - col[x] + gm; fprintf(f, "%d %d %.1f\n", x, y, dev); } } fclose(f); printf("captured %d frames (type0=%d type1=%d) -> %s\n", got, type0, type1, out); 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 0; }