初始化与构造
强烈建议使用 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;
}