跳到主要内容

异常处理

C++ SDK 使用异常机制报告错误,SDK 操作失败时抛出 DarraException

DarraException

class DarraException : public std::runtime_error {
public:
DarraException(int code, const std::string& msg);
DarraException(const std::string& msg);

/** 获取错误码 */
int code() const noexcept;
};

DarraException 继承自 std::runtime_error,包含错误码和错误消息。位于 darra::ethercat 命名空间。

构造方式:

  • DarraException(int code, const std::string& msg) — 带错误码
  • DarraException(const std::string& msg) — 不带错误码(默认 -1)

成员方法:

  • what() (const char*) — 错误消息(继承自 std::runtime_error)
  • code() (int) — 错误码

异常触发场景

SDK 在以下场景抛出 DarraException

场景说明
JSON 初始化失败EtherCATMaster_FromJson() / EtherCATMaster_FromJsonFile() 配置无效

CoEAccessDeniedException

CoE SDO 访问权限相关错误使用独立的异常类型 CoEAccessDeniedException, 同样位于 darra::ethercat 命名空间, 继承自 std::runtime_error

class CoEAccessDeniedException : public std::runtime_error {
public:
CoEAccessDeniedException(uint16_t index, uint8_t sub, const std::string& name,
bool isRead, uint16_t objAccess);

uint16_t Index() const;
uint8_t SubIndex() const;
bool IsReadOperation() const;
uint16_t ObjAccess() const;

static CoEAccessDeniedException CreateWithCustomMessage(
uint16_t index, uint8_t sub, const std::string& msg,
bool isRead, uint16_t objAccess);
};

成员方法:

方法类型说明
Index()uint16_tSDO 对象索引
SubIndex()uint8_t子索引
IsReadOperation()bool触发操作是否为读 (false=写)
ObjAccess()uint16_t对象访问位图 (ObjAccess)
what()const char*包含中文权限描述的可读消息

触发场景: 对只读对象写入、对只写对象读取、在当前 EtherCAT 状态下不允许的访问 (如 OP 写 PreOP-only 对象) 等。

示例:

try {
coe.SDOWriteU16(0x6041, 0, 0x0006); // StatusWord 是只读
} catch (const ethercat::CoEAccessDeniedException& e) {
printf("访问拒绝: idx=0x%04X sub=%u 读=%d (%s)\n",
e.Index(), e.SubIndex(), e.IsReadOperation(), e.what());
}
与 SdoError 的区别

SDO Abort Code (SdoError) 是底层从站返回的中止码, 通过 coe.LastSdoError() 查询, 不抛异常; CoEAccessDeniedException 是 SDK 在调用前根据对象字典访问位图主动判定的访问权限异常。

错误处理模式

异常捕获

#include "ethercat.hpp"
using namespace darra;

try {
EtherCATMaster master(dll);
master.SetNetwork("\\Device\\NPF_{...}")
.SetENI("config.deni")
.Build();
master.SetState(EcState::OP);
master.Start();
} catch (const ethercat::DarraException& e) {
printf("SDK 错误: %s (code=%d)\n", e.what(), e.code());
} catch (const std::exception& e) {
printf("标准错误: %s\n", e.what());
}

std::optional 返回值

大部分 Slave 和协议类方法使用 std::optional 表示可能失败的操作,不会抛出异常:

auto& slave = master.GetSlave(1);

// CoE 类型化读取(可能失败)
auto& coe = slave.GetCoE();
auto sw = coe.SDOReadU16(0x6041, 0); // std::optional<uint16_t>
if (sw) {
printf("StatusWord: 0x%04X\n", *sw);
} else {
printf("SDO 读取失败\n");
}

空 vector 返回值

数据读取方法返回空 std::vector<uint8_t> 表示失败:

auto& coe = slave.GetCoE();

// SDO 读取
auto data = coe.SDORead(0x6041, 0);
if (data.empty()) {
printf("SDO 读取失败\n");
return;
}

// FoE 文件读取
auto& foe = slave.GetFoE();
auto file = foe.Download("config.xml");
if (file.empty()) {
printf("文件读取失败\n");
}

bool 返回值

写入操作返回 bool 表示成功/失败:

auto& coe = slave.GetCoE();

bool ok = coe.SDOWriteU16(0x6040, 0, 0x0006);
if (!ok) {
printf("SDO 写入失败\n");
}

Build() 返回值

EtherCATMaster::Build() 返回 bool 而非抛出异常:

EtherCATMaster master(dll);
master.SetNetwork("\\Device\\NPF_{...}");
if (!master.Build()) {
printf("主站初始化失败\n");
return -1;
}

AL 错误分类

ALErrorClassifier 对从站 AL Status Code 进行分类,帮助快速判断错误性质和处理策略。

auto category = ALErrorClassifier::Classify(slave.ErrorCode());
switch (category) {
case ALErrorCategory::None: /* 无错误 */ break;
case ALErrorCategory::Transient: /* 瞬态错误,可重试 */ break;
case ALErrorCategory::Configuration: /* 配置错误,检查 PDO/SM */ break;
case ALErrorCategory::Hardware: /* 硬件错误,检查设备 */ break;
case ALErrorCategory::Unknown: /* 未知,查阅 ETG.1000 */ break;
}

详见 主站诊断 - AL 错误分类

错误处理最佳实践

#include "ethercat.hpp"
using namespace darra;

int main() {
try {
// Build 返回 bool
EtherCATMaster master(dll);
master.SetNetwork("\\Device\\NPF_{...}")
.SetENI("config.deni");
if (!master.Build()) {
printf("初始化失败\n");
return -1;
}

auto& slave = master.GetSlave(1);

// 协议操作使用 optional/bool 检查
auto& coe = slave.GetCoE();
if (auto sw = coe.SDOReadU16(0x6041, 0)) {
printf("StatusWord: 0x%04X\n", *sw);
}

if (!coe.SDOWriteU16(0x6040, 0, 0x0006)) {
printf("ControlWord 写入失败\n");
}

// Start/Stop 返回 bool
master.SetState(EcState::OP);
if (!master.Start()) {
printf("启动失败\n");
}

getchar();

} catch (const ethercat::DarraException& e) {
fprintf(stderr, "DarraEtherCAT 错误: %s (code=%d)\n",
e.what(), e.code());
return 1;
}
return 0;
}