// ============================================================
//  wrapper_v2.cpp  — 超简版，C 基础就能看
//
//  总共 5 个函数：
//     ic_start()        — 打开加密狗
//     ic_stop()         — 关加密狗
//     cam_init()        — 初始化相机
//     cam_capture()     — 拍一帧（左+右图）
//     cam_close()       — 关相机
//
//  原理只有一句话：
//     用 LoadLibrary 加载 DLL，用 GetProcAddress 找到函数，调用它
// ============================================================

#include <windows.h>
#include <stdio.h>

// ---- 5个导出函数声明 ----
__declspec(dllexport) int   ic_start(void);
__declspec(dllexport) void  ic_stop(void);
__declspec(dllexport) int   cam_init(void);
__declspec(dllexport) int   cam_capture(unsigned char* left, unsigned char* right, int* w, int* h);
__declspec(dllexport) void  cam_close(void);

// ---- DLL 句柄 ----
static HMODULE hIC, hCam, hONI;
static void*   g_dev;    // 相机设备句柄
static void*   g_stream; // 数据流句柄

// ---- 下面是一堆 GetProcAddress 函数指针 ----
// 看不懂没关系，反正后面都是模板代码，照抄就行

static int  (*pIC_Start)();
static void (*pIC_Stop)();
static int  (*pInitCam)(int a, int b);     // ← 【待确认1】InitUseCam2011 的参数
static int  (*pOniInit)();
static int  (*pOniGetDevList)(void**, int*);
static int  (*pOniDevOpen)(const char*, void**);
static int  (*pOniDevClose)(void*);
static int  (*pOniCreateStream)(void*, int, void**);
static int  (*pOniStreamStart)(void*);
static int  (*pOniStreamStop)(void*);
static int  (*pOniReadFrame)(void*, void**, int);
static void (*pOniFreeFrame)(void*);

// ---- 加载 DLL + 获取函数 ----
#define LOAD_DLL(h, name)                   \
    h = LoadLibraryA(name);                 \
    if (!h) { printf("❌ 加载 %s 失败\n", name); return -1; }

#define GET_FUNC(h, name, ptr)              \
    *(void**)&ptr = GetProcAddress(h, name);\
    if (!ptr) { printf("❌ 未找到 %s\n", name); return -2; }

// ============================================================
//  ① ic_start — 打开加密狗
// ============================================================
__declspec(dllexport) int ic_start()
{
    LOAD_DLL(hIC, "ICDevice.dll");
    GET_FUNC(hIC, "IC_Start", pIC_Start);
    GET_FUNC(hIC, "IC_Stop",  pIC_Stop);

    int r = pIC_Start();
    // ↓ 如果 IC_Start() 返回值不是 0，试试改为 TRUE/FALSE 判断
    if (r != 0) { printf("❌ IC_Start 返回 %d\n", r); return -3; }
    printf("✅ 加密狗已打开\n");
    return 0;
}

// ============================================================
//  ② ic_stop — 关闭加密狗
// ============================================================
__declspec(dllexport) void ic_stop()
{
    if (pIC_Stop) pIC_Stop();
    if (hIC)      FreeLibrary(hIC);
    printf("✅ 加密狗已关闭\n");
}

// ============================================================
//  ③ cam_init — 初始化相机
// ============================================================
__declspec(dllexport) int cam_init()
{
    // 第一步：加载相机硬件 DLL
    LOAD_DLL(hCam, "xhcv2011.dll");
    GET_FUNC(hCam, "InitUseCam2011", pInitCam);

    /* ======================================================
       【待确认1】InitUseCam2011 需要什么参数？
       当前猜测：pInitCam(a, b)
       请在下面填上实际参数值。例如：
         int r = pInitCam(0, 0);     // 可能不需要参数
         int r = pInitCam(1, 0);     // 第一个相机
       ====================================================== */
    int r = pInitCam(0, 0);   // ← 请根据实际接口修改
    if (r != 0) { printf("❌ InitUseCam2011 返回 %d\n", r); return -4; }
    printf("✅ 相机硬件初始化完成\n");

    // 第二步：加载 OpenNI2
    LOAD_DLL(hONI, "OpenNI2.dll");
    GET_FUNC(hONI, "oniInitialize",      pOniInit);
    GET_FUNC(hONI, "oniGetDeviceList",   pOniGetDevList);
    GET_FUNC(hONI, "oniDeviceOpen",      pOniDevOpen);
    GET_FUNC(hONI, "oniDeviceClose",     pOniDevClose);
    GET_FUNC(hONI, "oniDeviceCreateStream", pOniCreateStream);
    GET_FUNC(hONI, "oniStreamStart",     pOniStreamStart);
    GET_FUNC(hONI, "oniStreamStop",      pOniStreamStop);
    GET_FUNC(hONI, "oniStreamReadFrame", pOniReadFrame);

    r = pOniInit();
    if (r != 0) { printf("❌ oniInitialize 返回 %d\n", r); return -5; }

    // 发现设备
    void* devList = NULL;
    int   devCnt  = 0;
    r = pOniGetDevList(&devList, &devCnt);
    if (r != 0 || devCnt < 1) { printf("❌ 未发现相机\n"); return -6; }
    printf("✅ 发现 %d 个设备\n", devCnt);

    /* ======================================================
       【待确认2】oniDeviceOpen 需要什么 URI？
       当前用的是 NULL（自动选第一个）
       如果不行，试试：
         pOniDevOpen("0000", &g_dev);     // 用设备索引
         pOniDevOpen("", &g_dev);         // 空字符串
       ====================================================== */
    r = pOniDevOpen(NULL, &g_dev);   // ← 如果报错请换参数
    if (r != 0) { printf("❌ 打开设备失败 %d\n", r); return -7; }
    printf("✅ 设备已打开\n");

    /* ======================================================
       【待确认3】sensor_type 参数值是多少？
       ONI_SENSOR_DEPTH = 1?  ONI_SENSOR_IR = 2?  ONI_SENSOR_COLOR = 3?
       ====================================================== */
    r = pOniCreateStream(g_dev, 1 /* ← 如果不对，试试 2 或 3 */, &g_stream);
    if (r != 0) { printf("❌ 创建流失败 %d\n", r); return -8; }
    printf("✅ 数据流已创建\n");

    return 0;
}

// ============================================================
//  ④ cam_capture — 拍一帧（左+右图）
// ============================================================
__declspec(dllexport) int cam_capture(unsigned char* left, unsigned char* right, int* w, int* h)
{
    if (!left || !right || !w || !h) return -9;

    pOniStreamStart(g_stream);

    void* frame = NULL;
    int r = pOniReadFrame(g_stream, &frame, 5000);
    if (r != 0 || !frame) {
        printf("❌ 读帧失败 %d\n", r);
        pOniStreamStop(g_stream);
        return -10;
    }

    /* ======================================================
       【待确认4】左右图怎么从帧里取出来？
       这是最核心的问题，到这一步需要实际测试。
       
       猜测几种可能：
       A) 一个帧里同时包含左右图 → 
          memcpy(left,  frame + 偏移, 宽*高);
          memcpy(right, frame + 偏移, 宽*高);
          
       B) 左右图分别在不同的流里 → 需要打开两个流
       
       C) 帧数据是 YUV/深度格式 → 需要转换
       
       先默认返回 640x512 的测试图：
       ====================================================== */
    *w = 640;
    *h = 512;
    memset(left,  0x80, 640*512);  // ← 灰色测试图，确认接口后在下面改
    memset(right, 0x40, 640*512);

    pOniFreeFrame(frame);
    pOniStreamStop(g_stream);
    printf("✅ 采集一帧 %dx%d\n", *w, *h);
    return 0;
}

// ============================================================
//  ⑤ cam_close — 关闭相机
// ============================================================
__declspec(dllexport) void cam_close()
{
    if (g_stream) pOniStreamStop(g_stream);
    if (g_dev)    pOniDevClose(g_dev);
    if (hONI)     FreeLibrary(hONI);
    if (hCam)     FreeLibrary(hCam);
    printf("✅ 相机已关闭\n");
}
