跳到主要内容

初始化与构造

推荐方式

强烈建议使用 Darra 配置工具导出的 DENI 文件进行初始化。DENI 文件包含完整的网络配置 (网口、从站、PDO 映射、DC 设置等), 可确保配置的一致性和正确性。

构造函数

EtherCATMaster(dll)

explicit EtherCATMaster(dll_t& dll);

创建主站实例。需要随后调用 SetNetwork() 和 Build() 完成初始化。

示例:

using namespace darra;
EtherCATMaster master(dll);

Builder 模式初始化 (推荐)

EtherCATMaster 支持链式 Builder 模式, 通过 SetNetwork、SetENI、EnableAutoStartup 配置后调用 Build 完成初始化。

EtherCATMaster master(dll);
bool ok = master.SetNetwork("\\Device\\NPF_{...}")
.SetENI("C:/EtherCAT/config.deni")
.Build();

SetNetwork()

EtherCATMaster& SetNetwork(const std::string& primary, const std::string& redundant = "");

设置主网口和可选的冗余网口。返回自身引用支持链式调用。

SetENI()

EtherCATMaster& SetENI(const std::string& path);

加载 ENI / DENI 配置文件。返回自身引用支持链式调用。

EnableAutoStartup()

EtherCATMaster& EnableAutoStartup();

标记需要自动配置从站 (Build 时执行)。返回自身引用支持链式调用。

备注

如果使用 ENI / DENI 文件, 通常不需要调用此方法。已有启动参数的从站会被完整跳过, 不会被覆盖或补充。此方法仅对未配置的从站生效 (自动从 ESI / MDP / SM 生成 PDO / DC / 启动参数)。

Validate()

ValidationResult Validate() const;

Build 前配置预检查, 不执行实际初始化。返回验证结果, 包含是否通过和错误列表。

相关结构:

struct ValidationResult {
bool IsValid; // 验证是否通过
std::vector<std::string> Errors; // 验证错误列表 (通过时为空)
};

示例:

auto result = master.Validate();
if (!result.IsValid) {
for (auto& err : result.Errors) printf("验证错误: %s\n", err.c_str());
return -1;
}
master.Build();

Build()

bool Build();

构建并初始化主站。返回 bool 表示是否成功。失败时实例已自动释放。

示例:

EtherCATMaster master(dll);
bool ok = master.SetNetwork("\\Device\\NPF_{...}")
.SetENI("C:/EtherCAT/config.deni")
.EnableAutoStartup()
.Build();

静态工厂方法

EtherCATMaster_FromJson()

namespace darra::ethercat {
EtherCATMaster EtherCATMaster_FromJson(dll_t& dll, const std::string& json_config);
}

通过 JSON 配置字符串一步初始化。失败抛出 DarraException。

EtherCATMaster_FromJsonFile()

namespace darra::ethercat {
EtherCATMaster EtherCATMaster_FromJsonFile(dll_t& dll, const std::string& path);
}

通过 JSON 文件一步初始化。失败抛出 DarraException。

InitializeSpecificMaster()

static std::optional<EtherCATMaster> InitializeSpecificMaster(dll_t& dll, uint16_t masterIndex);

初始化指定索引的主站。与 Build() 不同, 此方法指定主站编号而非自动分配 (不允许 0)。失败返回 std::nullopt。

独立 MasterBuilder 类

namespace darra::ethercat {
class MasterBuilder {
public:
explicit MasterBuilder(dll_t& dll);
MasterBuilder& SetNetwork(const std::string& primary, const std::string& secondary = "");
MasterBuilder& SetENI(const std::string& path);
MasterBuilder& SetEsiFiles(const std::string& path);
MasterBuilder& EnableAutoStartup();
MasterBuilder& SetRevisionMatch(ScanRevisionMatchMode mode);
BuildResult Build();
};
}

返回 BuildResult 结构体的独立 Builder。

相关结构:

struct BuildResult {
bool Success; // 是否成功
std::string Message; // 描述消息
uint16_t MasterIndex; // 成功时为有效索引, 失败时为 0xFFFF
};

示例:

using namespace darra::ethercat;

auto result = MasterBuilder(dll)
.SetNetwork("\\Device\\NPF_{...}")
.SetENI("config.xml")
.Build();

if (result.Success) printf("主站索引: %d\n", result.MasterIndex);

RAII 生命周期

EtherCATMaster 遵循 RAII 原则: 构造时创建, 析构时自动释放。无需手动调用 Dispose()。

{
EtherCATMaster master(dll);
master.SetNetwork("\\Device\\NPF_{...}");
master.Build();
master.SetState(EcState::OP);
master.Start();
} // 离开作用域, 析构自动 Stop -> Dispose

Dispose()

void Dispose();

手动释放主站资源。析构函数会自动调用, 通常无需手动调用。

EmergencyCleanup() (静态)

static void EmergencyCleanup(dll_t& dll);

紧急清理所有主站资源, 释放网卡句柄。在进程异常退出或信号处理中调用。

移动语义

EtherCATMaster 支持移动构造, 但禁止拷贝, 确保资源唯一所有权。

EtherCATMaster master1(dll);
EtherCATMaster master2 = std::move(master1);
// master1 现在无效, master2 拥有资源

容器存储:

auto master = std::make_unique<EtherCATMaster>(dll);
master->SetNetwork("\\Device\\NPF_{...}");
master->Build();

多实例管理

每个 EtherCATMaster 实例管理一条独立的 EtherCAT 总线, 使用不同的网卡。创建新实例无需重启, 即时生效。

ActiveInstanceCount() / MaxInstanceCount()

static int ActiveInstanceCount();
static int MaxInstanceCount(dll_t& dll);

查询当前活跃的主站实例数量和允许的最大主站实例数量。

示例:

EtherCATMaster master1(dll);
master1.SetNetwork(adapters[0].name);
master1.EnableAutoStartup();
master1.Build();

EtherCATMaster master2(dll);
master2.SetNetwork(adapters[1].name);
master2.EnableAutoStartup();
master2.Build();

printf("活跃主站数: %d\n", EtherCATMaster::ActiveInstanceCount());
多实例要求
  • 每个实例必须使用不同的网卡 — 同一网卡不能被多个实例同时使用
  • CPU 核心自动分配 — 每个实例自动占用不同的 CPU 核心
  • Mailbox Gateway 端口自动偏移 — 每个实例自动分配不同的端口号
  • 授权与日志共享 — 所有实例共享同一授权状态和日志系统

网络扫描

GetAvailableNetworks()

namespace darra::ethercat {
std::vector<NetworkInfo> GetAvailableNetworks(dll_t& dll,
bool isRedundant = false,
bool needSlaveCount = false);
}

获取系统中可用的网络适配器列表。

相关结构:

struct NetworkInfo {
std::string name; // 网卡标识 (如 \\Device\\NPF_{...})
std::string desc; // 网卡描述
int slaveCount; // 扫描到的从站数量 (仅 needSlaveCount=true 时有效)
};

示例:

using namespace darra::ethercat;
auto adapters = GetAvailableNetworks(dll, false, true);
for (const auto& a : adapters) printf("%s: %d 个从站\n", a.desc.c_str(), a.slaveCount);

Scan() / ConfigMap()

namespace darra::ethercat {
int Scan(EtherCATMaster& m, ScanRevisionMatchMode revisionMatch = ScanRevisionMatchMode::IgnoreRevision);
int ConfigMap(EtherCATMaster& m);
int ConfigMapGroup(EtherCATMaster& m, uint8_t group);
}

扫描从站、配置 IOmap、按组配置 IOmap。

完整示例

#include "ethercat.hpp"
using namespace darra;
using namespace darra::ethercat;

int main() {
try {
EtherCATMaster master(dll);
master.SetENI("C:/EtherCAT/MyProject.deni").Build();

master.SetState(EcState::OP);
master.Start();

printf("主站 %d: %d 个从站\n", master.MasterNumber(), master.SlaveCount());
getchar();
} catch (const DarraException& e) {
printf("错误: %s\n", e.what());
return -1;
}
return 0;
}