/**
 * CAN API 快速参考
 * 基于 ControlCAN 接口函数库
 */

// ============================================
// 1. 基本数据结构
// ============================================

// CAN 帧结构
typedef struct {
    UINT   ID;              // CAN ID
    UINT   TimeStamp;       // 时间戳（0.1ms）
    BYTE   TimeFlag;        // 时间标志
    BYTE   SendType;        // 0=正常发送, 1=单次发送
    BYTE   RemoteFlag;      // 0=数据帧, 1=远程帧
    BYTE   ExternFlag;      // 0=标准帧(11位), 1=扩展帧(29位)
    BYTE   DataLen;         // 数据长度(0-8)
    BYTE   Data[8];         // 数据
} VCI_CAN_OBJ;

// 初始化配置
typedef struct {
    DWORD  AccCode;         // 验收码
    DWORD  AccMask;         // 屏蔽码（0xFFFFFFFF=接收所有）
    DWORD  Reserved;
    BYTE   Filter;          // 滤波方式（1=所有类型）
    BYTE   Timing0;         // 波特率 T0
    BYTE   Timing1;         // 波特率 T1
    BYTE   Mode;            // 0=正常, 1=只听, 2=自发自收
} VCI_INIT_CONFIG;

// 设备信息
typedef struct {
    USHORT hw_Version;      // 硬件版本
    USHORT fw_Version;      // 固件版本
    BYTE   can_Num;         // CAN 通道数
    CHAR   str_Serial_Num[20];  // 序列号
} VCI_BOARD_INFO;

// ============================================
// 2. 核心 API 函数
// ============================================

// 打开设备
DWORD VCI_OpenDevice(DWORD DevType, DWORD DevIndex, DWORD Reserved);
// 参数：DevType=4(USBCAN2), DevIndex=设备索引(0,1,2...)
// 返回：1=成功, 0=失败, -1=设备不存在

// 关闭设备
DWORD VCI_CloseDevice(DWORD DevType, DWORD DevIndex);

// 初始化 CAN
DWORD VCI_InitCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex,
                  PVCI_INIT_CONFIG pInitConfig);
// 参数：CANIndex=CAN通道(0=CAN0, 1=CAN1)

// 启动 CAN
DWORD VCI_StartCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex);

// 复位 CAN
DWORD VCI_ResetCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex);

// 发送数据
DWORD VCI_Transmit(DWORD DevType, DWORD DevIndex, DWORD CANIndex,
                   PVCI_CAN_OBJ pSend, DWORD Len);
// 返回：实际发送的帧数

// 接收数据
DWORD VCI_Receive(DWORD DevType, DWORD DevIndex, DWORD CANIndex,
                  PVCI_CAN_OBJ pReceive, DWORD Len, INT WaitTime);
// 返回：实际接收的帧数

// 获取接收数量
DWORD VCI_GetReceiveNum(DWORD DevType, DWORD DevIndex, DWORD CANIndex);

// 清空缓冲区
DWORD VCI_ClearBuffer(DWORD DevType, DWORD DevIndex, DWORD CANIndex);

// 读取设备信息
DWORD VCI_ReadBoardInfo(DWORD DevType, DWORD DevIndex, PVCI_BOARD_INFO pInfo);

// ============================================
// 3. 常用波特率配置
// ============================================

// 波特率      Timing0    Timing1
// 1000 Kbps   0x00       0x14
// 800 Kbps    0x00       0x16
// 500 Kbps    0x00       0x1C    // 推荐
// 250 Kbps    0x01       0x1C
// 125 Kbps    0x03       0x1C
// 100 Kbps    0x04       0x1C

// ============================================
// 4. 完整使用流程
// ============================================

void CAN_Example() {
    // 步骤1：打开设备
    if (VCI_OpenDevice(VCI_USBCAN2, 0, 0) != 1) {
        printf("打开设备失败\n");
        return;
    }

    // 步骤2：配置并初始化
    VCI_INIT_CONFIG config;
    config.AccCode = 0x00000000;
    config.AccMask = 0xFFFFFFFF;    // 接收所有
    config.Filter = 1;
    config.Timing0 = 0x00;          // 500Kbps
    config.Timing1 = 0x1C;
    config.Mode = 0;                // 正常模式

    if (VCI_InitCAN(VCI_USBCAN2, 0, 0, &config) != 1) {
        printf("初始化失败\n");
        VCI_CloseDevice(VCI_USBCAN2, 0);
        return;
    }

    // 步骤3：启动 CAN
    if (VCI_StartCAN(VCI_USBCAN2, 0, 0) != 1) {
        printf("启动失败\n");
        VCI_CloseDevice(VCI_USBCAN2, 0);
        return;
    }

    // 步骤4：清空缓冲区
    VCI_ClearBuffer(VCI_USBCAN2, 0, 0);

    // 步骤5：发送数据
    VCI_CAN_OBJ send_frame;
    memset(&send_frame, 0, sizeof(VCI_CAN_OBJ));
    send_frame.ID = 0x123;
    send_frame.SendType = 0;
    send_frame.RemoteFlag = 0;
    send_frame.ExternFlag = 0;      // 标准帧
    send_frame.DataLen = 8;
    send_frame.Data[0] = 0x11;
    send_frame.Data[1] = 0x22;
    // ...

    DWORD ret = VCI_Transmit(VCI_USBCAN2, 0, 0, &send_frame, 1);
    printf("发送 %d 帧\n", ret);

    // 步骤6：接收数据
    VCI_CAN_OBJ recv_frames[100];
    ret = VCI_Receive(VCI_USBCAN2, 0, 0, recv_frames, 100, 0);
    printf("接收 %d 帧\n", ret);

    for (DWORD i = 0; i < ret; i++) {
        printf("ID=0x%03X, 数据=[", recv_frames[i].ID);
        for (int j = 0; j < recv_frames[i].DataLen; j++) {
            printf("%02X ", recv_frames[i].Data[j]);
        }
        printf("]\n");
    }

    // 步骤7：关闭设备
    VCI_CloseDevice(VCI_USBCAN2, 0);
}

// ============================================
// 5. 常见应用场景
// ============================================

// 场景1：发送标准帧
void Send_StandardFrame(UINT id, BYTE* data, BYTE len) {
    VCI_CAN_OBJ frame = {0};
    frame.ID = id;
    frame.SendType = 0;
    frame.RemoteFlag = 0;
    frame.ExternFlag = 0;           // 标准帧
    frame.DataLen = len;
    memcpy(frame.Data, data, len);
    VCI_Transmit(VCI_USBCAN2, 0, 0, &frame, 1);
}

// 场景2：发送扩展帧
void Send_ExtendedFrame(UINT id, BYTE* data, BYTE len) {
    VCI_CAN_OBJ frame = {0};
    frame.ID = id;
    frame.SendType = 0;
    frame.RemoteFlag = 0;
    frame.ExternFlag = 1;           // 扩展帧
    frame.DataLen = len;
    memcpy(frame.Data, data, len);
    VCI_Transmit(VCI_USBCAN2, 0, 0, &frame, 1);
}

// 场景3：循环接收
void Receive_Loop() {
    VCI_CAN_OBJ frames[2500];
    while (running) {
        DWORD count = VCI_Receive(VCI_USBCAN2, 0, 0, frames, 2500, 0);
        if (count > 0) {
            // 处理接收到的数据
            for (DWORD i = 0; i < count; i++) {
                Process_Frame(&frames[i]);
            }
        }
        Sleep(10);  // 10ms 间隔
    }
}

// 场景4：AGV 速度控制
void AGV_SetVelocity(int16_t left_rpm, int16_t right_rpm) {
    BYTE data[8] = {0};
    data[0] = 0x10;  // 速度命令
    data[1] = 0x00;
    data[2] = (left_rpm >> 8) & 0xFF;   // 左轮高字节
    data[3] = left_rpm & 0xFF;          // 左轮低字节
    data[4] = (right_rpm >> 8) & 0xFF;  // 右轮高字节
    data[5] = right_rpm & 0xFF;         // 右轮低字节

    Send_StandardFrame(0x200, data, 8);
}

// ============================================
// 6. 错误处理
// ============================================

// 检查返回值
DWORD ret = VCI_OpenDevice(VCI_USBCAN2, 0, 0);
if (ret == 0) {
    printf("操作失败\n");
} else if (ret == (DWORD)-1) {
    printf("设备不存在或 USB 掉线\n");
} else {
    printf("操作成功\n");
}

// ============================================
// 7. 注意事项
// ============================================

/*
1. 一个设备只能打开一次
2. 发送帧数建议每次 1 帧，提高效率
3. 接收缓冲区建议 2500 帧
4. 多节点通信时 SendType 必须为 0
5. 扩展帧 ID 为 29 位，标准帧为 11 位
6. 数据长度最大 8 字节
7. 波特率配置要与总线其他设备一致
8. 使用完毕后记得关闭设备
*/
