
#define DYNAMIC_LOAD
#include "ethercat.h"

#include <stdio.h>
#include <string.h>

static void on_log(int category, const char* message)
{
    const char* tags[] = {"错误", "警告", "消息", "邮箱", "PDO", "调试"};
    const char* tag = (category >= 0 && category <= 5) ? tags[category] : "未知";
    printf("[%s] %s\n", tag, message);
}

static void on_pdo_cyclic(uint16_t master_index)
{

}

int main(int argc, char* argv[])
{
    dll_t dll;
    uint16_t master;
    const char* adapter;

    printf("=== DarraEtherCAT C SDK 基础示例 ===\n\n");

    if (!LOAD_DLL(&dll, "Darra.Core.dll")) {
        printf("错误: 无法加载 Darra.Core.dll\n");
        printf("请确保 DLL 文件在当前目录或 PATH 路径中\n");
        return 1;
    }
    printf("DLL 加载成功\n");

    if (dll.GetDllVersionInfo) {
        const version_info_t* ver = dll.GetDllVersionInfo();
        if (ver) {
            printf("版本: %d.%d.%d.%d (%s)\n",
                   ver->major, ver->minor, ver->patch, ver->build, ver->build_date);
        }
    }

    if (dll.SetLogCallback) {
        dll.SetLogCallback(on_log);
    }

    master = dll.Initialize();
    if (master == 0) {
        printf("错误: 主站初始化失败\n");
        UNLOAD_DLL(&dll);
        return 1;
    }
    printf("主站初始化成功, 索引: %d\n", master);

    if (argc < 2) {
        printf("用法: %s <网卡名称> [冗余网卡名称]\n", argv[0]);
        printf("\n提示: 先运行 GetNetworkInfo 获取可用网卡列表\n");
        dll.Dispose(master);
        UNLOAD_DLL(&dll);
        return 1;
    }

    adapter = argv[1];
    {
        const char* secondary = (argc >= 3) ? argv[2] : "";
        uint16_t ret = dll.SetNetwork(master, adapter, secondary);
        if (ret == 0 || ret == 0xFFFF) {
            printf("错误: 网络绑定失败 (返回值: %u)\n", ret);
            dll.Dispose(master);
            UNLOAD_DLL(&dll);
            return 1;
        }
        printf("网络绑定成功, 从站数量: %d\n", ret);
    }

    printf("开始状态转换...\n");

    if (!dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000)) {
        printf("错误: 状态转换失败\n");
        dll.Dispose(master);
        UNLOAD_DLL(&dll);
        return 1;
    }
    printf("已进入 Operational 状态\n");

    if (dll.RegisterPDOCyclicSync) {
        dll.RegisterPDOCyclicSync(on_pdo_cyclic);
    }
    dll.Start(master);
    printf("PDO 循环已启动\n");

    {
        int32_t out_size = 0, in_size = 0;
        uint8_t* out_ptr = NULL;
        uint8_t* in_ptr = NULL;
        uint16_t slave_index = 1;

        uint8_t ret = dll.GetIO(master, slave_index, &out_size, &out_ptr, &in_size, &in_ptr);
        if (ret == 0) {
            printf("从站 %d: 输出 %d 字节, 输入 %d 字节\n", slave_index, out_size, in_size);

            if (out_ptr && out_size > 0) {
                printf("输出数据 (前 %d 字节):", out_size > 8 ? 8 : out_size);
                for (int i = 0; i < out_size && i < 8; i++) {
                    printf(" %02X", out_ptr[i]);
                }
                printf("\n");
            }

            if (in_ptr && in_size > 0) {
                printf("输入数据 (前 %d 字节):", in_size > 8 ? 8 : in_size);
                for (int i = 0; i < in_size && i < 8; i++) {
                    printf(" %02X", in_ptr[i]);
                }
                printf("\n");
            }

            if (out_size >= 1) {
                uint8_t value = 0x06;
                dll.WriteSlaveOutputByte(master, slave_index, 0, value);
            }
        }
    }

    {
        int sdo_size = 0;
        char* sdo_data = dll.dx_sdo_read(master, 1, 0x1018, 0x01, FALSE, &sdo_size);
        if (sdo_data && sdo_size > 0) {
            uint32_t vendor_id = 0;
            memcpy(&vendor_id, sdo_data, sdo_size > 4 ? 4 : sdo_size);
            printf("从站1 Vendor ID: 0x%08X\n", vendor_id);
            dll.FreeMemory(sdo_data);
        }
    }

    printf("\n按 Enter 键停止...\n");
    getchar();

    printf("正在停止...\n");
    dll.Stop(master);
    dll.ClearStartupParameters(master, 0);
    dll.Dispose(master);
    UNLOAD_DLL(&dll);
    printf("已退出\n");

    return 0;
}
