跳到主要内容

初始化

推荐方式

强烈建议使用 Darra 配置工具导出的 DENI 文件进行初始化。
DENI 文件包含完整的网络配置(网口、从站、PDO 映射、DC 设置等),可确保配置的一致性和正确性。
使用 DENI 文件管理设备硬件设施将获得更好的兼容性与通用性。

创建主站

C SDK 通过函数指针表 dll_t 加载 Darra.Core.dll,主站索引 master_index 作为所有后续 API 的第一个参数。

Initialize()

uint16_t Initialize(void);
uint16_t InitializeSpecificMaster(uint16_t master_index);
int GetMaxMasterInstances(void);

Initialize() 创建一个新的主站实例并返回其索引(>0 成功,0 失败)。InitializeSpecificMaster() 初始化指定索引的主站(不允许索引 0)。GetMaxMasterInstances() 返回允许的最大主站实例数。

SetNetwork()

uint16_t SetNetwork(uint16_t master_index, const char* if_primary, const char* if_secondary);

绑定网卡。if_secondary 传空字符串 "" 表示单网卡模式。

参数:

  • master_index (uint16_t) — 主站索引
  • if_primary (const char*) — 主网卡名称(Windows: \\Device\\NPF_{GUID},Linux: eth0
  • if_secondary (const char*) — 冗余网卡名称("" 表示无冗余)

返回值:

  • uint16_t — 发现的从站数量,0 或 0xFFFF 表示失败

示例:

dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");

uint16_t master = dll.Initialize();
uint16_t slave_count = dll.SetNetwork(master, "\\Device\\NPF_{GUID}", "");
printf("发现 %d 个从站\n", slave_count);

资源释放

Dispose()

void Dispose(uint16_t master_index);
void FreeMemory(void* ptr);
void EmergencyCloseNics(void);
  • Dispose() 释放主站实例。调用后 master_index 不可再使用。
  • FreeMemory() 释放 SDK 内部分配的内存(如 GetSerialNumber() 返回的字符串)。
  • EmergencyCloseNics() 紧急关闭所有网卡句柄,在进程异常退出(信号处理 / atexit)时调用。

多实例管理

每个主站实例管理一条独立的 EtherCAT 总线,使用不同的网卡。Initialize() 多次调用即可创建多个实例。

多实例要求
  • 每个实例必须使用不同的网卡(同一网卡不能被多个实例同时使用)
  • CPU 核心由 SDK 自动分配,不同实例占用不同核心
  • Mailbox Gateway 端口自动按实例索引偏移
  • 授权与日志在所有实例间共享
uint16_t master1 = dll.Initialize();
dll.SetNetwork(master1, "\\Device\\NPF_{GUID_A}", "");

uint16_t master2 = dll.Initialize();
dll.SetNetwork(master2, "\\Device\\NPF_{GUID_B}", "");

dll.SetStateSequence(master1, EC_STATE_OPERATIONAL, 10000);
dll.SetStateSequence(master2, EC_STATE_OPERATIONAL, 10000);

dll.Dispose(master1);
dll.Dispose(master2);

网络扫描

GetNetworkInfo()

int   GetNetworkInfo(BOOL is_redundant, BOOL need_slaves_num);
void* GetNetworksPointer(void);

GetNetworkInfo() 扫描系统中可用的网卡并返回数量。need_slaves_num=TRUE 时同时为每张 NIC 做 BRD 探测填充从站数 + 自动识别冗余对(耗时约 500ms – 1.5s);FALSE 时仅列举 NIC(耗时约 100ms)。GetNetworksPointer() 返回内部网卡列表指针,无需释放。

QuickSlaveCount()

int QuickSlaveCount(const char* adapter_name);
int QuickSlaveCountRedundant(const char* primary, const char* secondary);
int ScanSlaveCount(const char* adapter_name);
int ScanSlaveCountRedundant(const char* primary, const char* secondary);
int GetRingSlaveCount(void);
int QuickFindRedundantPairBatch(const char** adapter_names, int adapter_count,
int* primary_idx, int* secondary_idx);
  • QuickSlaveCount* — 不读 EEPROM,仅广播查询,返回从站数量。
  • ScanSlaveCount* — 完整扫描(读取 EEPROM)。
  • GetRingSlaveCount() — 上一次冗余扫描中环上的从站数。
  • QuickFindRedundantPairBatch() — 在多张 NIC 中批量探测冗余对,输出主/副适配器索引。

ReadSlaveInfo()

int  ReadSlaveInfo(const char* adapter_name);
int GetScannedSlaveCount(void);
BOOL GetScannedSlaveInfo(int index,
uint32_t* vendor_id, uint32_t* product_code,
uint32_t* revision, uint32_t* serial,
char* name, int name_size,
uint16_t* config_addr, uint16_t* alias_addr,
uint16_t* parent, uint8_t* topology, uint8_t* activeports,
uint8_t* entryport, uint8_t* parentport, uint8_t* ptype);

ReadSlaveInfo() 扫描指定网卡上所有从站并缓存详情,返回从站数量。配合 GetScannedSlaveCount()GetScannedSlaveInfo() 按索引读取每个从站的厂商 ID / 产品代码 / 拓扑信息等(index 0-based)。

示例:

int count = dll.ReadSlaveInfo("\\Device\\NPF_{GUID}");
for (int i = 0; i < count; i++) {
uint32_t vid, pid, rev, serial;
char name[128];
uint16_t cfg_addr, alias, parent;
uint8_t topo, ports, entry, pport, ptype;
if (dll.GetScannedSlaveInfo(i, &vid, &pid, &rev, &serial,
name, sizeof(name), &cfg_addr, &alias,
&parent, &topo, &ports, &entry, &pport, &ptype)) {
printf("[%d] %s (VID=0x%08X, PID=0x%08X)\n", i + 1, name, vid, pid);
}
}

AbortScan()

void AbortScan(void);
void ResetScanAbort(void);
void AbortNetwork(void);
void ResetAbortNetwork(void);

中止/重置正在进行的网络扫描操作。AbortScan() 用于关闭 UI 窗口或取消操作时快速中断阻塞的扫描;AbortNetwork() 作用于网络层(绑定/通讯)的取消。

一步初始化 (EcInit)

EcInit()

uint16_t EcInit(const char* json_config);
uint16_t EcInitFromFile(const char* json_file_path);
void EcClose(uint16_t master_index);

EcInit() 通过 JSON 字符串一步完成 Initialize + SetNetwork + LoadConfig + SetStateSequence + StartEcInitFromFile() 从文件读取 JSON。EcClose() 一步关闭并释放,配对使用。

JSON 配置:

{
"adapter": "\\Device\\NPF_{GUID}",
"redundant_adapter": "",
"cycle_time_us": 1000,
"dc_sync0_ns": 1000000,
"target_state": "OP",
"slaves": []
}

字段说明:

  • adapter (必选) — 主网卡名称
  • redundant_adapter (可选) — 冗余网卡名称(空字符串=单网卡)
  • cycle_time_us (可选) — PDO 周期,默认 1000
  • dc_sync0_ns (可选) — DC SYNC0 周期,0=不配置 DC
  • target_state (可选) — 目标状态("OP"/"SAFEOP"/"PREOP")
  • slaves (可选) — 从站启动参数配置数组

版本与授权

GetSerialNumber()

/* 返回值需要调用 FreeMemory() 释放 */
char* GetSerialNumber(void);
char* GetDeviceName(void);
char* GetUserEmail(void);
int VerifyLicense(void);
BOOL IsLicenseValid(void);

获取设备序列号 / 设备名称 / 用户邮箱(用于授权验证)。VerifyLicense() 返回 0 表示授权有效,IsLicenseValid() 返回当前授权状态。返回字符串指针的 API 必须调用 FreeMemory() 释放。

示例:

char* serial = dll.GetSerialNumber();
if (serial) {
printf("设备序列号: %s\n", serial);
dll.FreeMemory(serial);
}

完整示例

使用 ENI/DENI 文件(推荐)

#define DYNAMIC_LOAD
#include "ethercat.h"
#include <stdio.h>

int main(void)
{
dll_t dll;
if (!LOAD_DLL(&dll, "Darra.Core.dll")) return 1;

uint16_t master = dll.Initialize();
if (master == 0) { UNLOAD_DLL(&dll); return 1; }

uint16_t ret = dll.SetNetwork(master, "\\Device\\NPF_{GUID}", "");
if (ret == 0 || ret == 0xFFFF) {
dll.Dispose(master); UNLOAD_DLL(&dll); return 1;
}
printf("发现 %d 个从站\n", ret);

if (!dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000)) {
dll.Dispose(master); UNLOAD_DLL(&dll); return 1;
}
dll.Start(master);

getchar();

dll.Stop(master);
dll.ClearStartupParameters(master, 0);
dll.Dispose(master);
UNLOAD_DLL(&dll);
return 0;
}

动态扫描网口

dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");

int adapter_count = dll.GetNetworkInfo(FALSE, TRUE);
printf("发现 %d 个网络适配器\n", adapter_count);

int slave_count = dll.ReadSlaveInfo("\\Device\\NPF_{GUID}");
for (int i = 0; i < slave_count; i++) {
/* 通过 GetScannedSlaveInfo() 读取详情 */
}

uint16_t master = dll.Initialize();
dll.SetNetwork(master, "\\Device\\NPF_{GUID}", "");
dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000);
dll.Start(master);

一步初始化

dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");

uint16_t master = dll.EcInitFromFile("config.json");
if (master == 0) { UNLOAD_DLL(&dll); return 1; }

/* ... 业务逻辑 ... */

dll.EcClose(master);
UNLOAD_DLL(&dll);