跳到主要内容

Browse (C)

DarraUa_Session_BrowseNode(h, node_id, filter, &res) — 列出指定节点的直接子节点 (一层).

前置阅读 / 配套

API

DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_BrowseNode(
DarraUa_SessionHandle h,
const char* node_id_str,
DarraUa_NodeClass filter_node_class,
DarraUa_BrowseResult** out_result);

DARRA_OPCUA_API uint32_t DARRA_OPCUA_CALL
DarraUa_BrowseResult_GetCount(const DarraUa_BrowseResult* r);

DARRA_OPCUA_API const DarraUa_ReferenceDescription* DARRA_OPCUA_CALL
DarraUa_BrowseResult_GetReference(const DarraUa_BrowseResult* r, uint32_t index);

DARRA_OPCUA_API void DARRA_OPCUA_CALL
DarraUa_BrowseResult_Delete(DarraUa_BrowseResult* r);

out_result 由 Stack 分配, 用 _Delete 释放. 失败时 *out_result = NULL.

ReferenceDescription 字段访问器

DARRA_OPCUA_API const char* DARRA_OPCUA_CALL
DarraUa_Ref_GetBrowseName(const DarraUa_ReferenceDescription* rd);

DARRA_OPCUA_API const char* DARRA_OPCUA_CALL
DarraUa_Ref_GetDisplayName(const DarraUa_ReferenceDescription* rd);

DARRA_OPCUA_API int32_t DARRA_OPCUA_CALL
DarraUa_Ref_GetNodeClass(const DarraUa_ReferenceDescription* rd);

DARRA_OPCUA_API int32_t DARRA_OPCUA_CALL
DarraUa_Ref_GetNodeIdString(
const DarraUa_ReferenceDescription* rd,
char* buf, int32_t buf_size);

Get* 返回的 const char* 生命周期 = BrowseResult, 不要 free.


用法

DarraUa_BrowseResult* br = NULL;
DarraUa_Status st = DarraUa_Session_BrowseNode(
h, "ns=2;s=Boiler1",
DARRA_UA_NODE_CLASS_UNSPECIFIED,
&br);
if (!DARRA_UA_STATUS_IS_GOOD(st) || !br) {
fprintf(stderr, "Browse failed: %s\n", DarraUa_StatusName(st));
return;
}

uint32_t n = DarraUa_BrowseResult_GetCount(br);
char id_buf[128];
for (uint32_t i = 0; i < n; ++i) {
const DarraUa_ReferenceDescription* rd =
DarraUa_BrowseResult_GetReference(br, i);
if (!rd) continue;
int32_t nc = DarraUa_Ref_GetNodeClass(rd);
const char* name = DarraUa_Ref_GetBrowseName(rd);
const char* dname = DarraUa_Ref_GetDisplayName(rd);
DarraUa_Ref_GetNodeIdString(rd, id_buf, (int32_t)sizeof(id_buf));
printf(" [class=%d] %-20s %s -> %s\n",
nc, name ? name : "", dname ? dname : "", id_buf);
}

DarraUa_BrowseResult_Delete(br);

批量浏览 (BrowseNodes)

如果同时要浏览多个节点 (例如 GUI 初次展开树), 用 BrowseNodes 一次 RPC:

DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_BrowseNodes(
DarraUa_SessionHandle h,
const char* const* node_id_strs,
uint32_t count,
DarraUa_NodeClass filter_node_class,
DarraUa_BrowseResult** out_results); /* 调用方分配 count 个槽 */
const char* roots[] = { "i=85" /* Objects */, "i=86" /* Types */ };
DarraUa_BrowseResult* results[2] = { NULL };
DarraUa_Session_BrowseNodes(h, roots, 2,
DARRA_UA_NODE_CLASS_UNSPECIFIED, results);

for (uint32_t r = 0; r < 2; ++r) {
if (!results[r]) {
printf("%s: failed\n", roots[r]);
continue;
}
uint32_t cnt = DarraUa_BrowseResult_GetCount(results[r]);
printf("%s: %u children\n", roots[r], cnt);
DarraUa_BrowseResult_Delete(results[r]);
}

如果某个节点浏览失败, 对应槽位 results[i] = NULL, 不影响其他.


NodeClass filter

typedef enum {
DARRA_UA_NODE_CLASS_UNSPECIFIED = 0,
DARRA_UA_NODE_CLASS_OBJECT = 1,
DARRA_UA_NODE_CLASS_VARIABLE = 2,
DARRA_UA_NODE_CLASS_METHOD = 4,
DARRA_UA_NODE_CLASS_OBJECT_TYPE = 8,
DARRA_UA_NODE_CLASS_VARIABLE_TYPE = 16,
DARRA_UA_NODE_CLASS_REFERENCE_TYPE= 32,
DARRA_UA_NODE_CLASS_DATA_TYPE = 64,
DARRA_UA_NODE_CLASS_VIEW = 128
} DarraUa_NodeClass;

按位或可组合 (例如 OBJECT | VARIABLE).

/* 只看 Variable */
DarraUa_Session_BrowseNode(h, "ns=2;s=Boiler1",
DARRA_UA_NODE_CLASS_VARIABLE, &br);

/* 只看 Method */
DarraUa_Session_BrowseNode(h, "ns=2;s=Calculator",
DARRA_UA_NODE_CLASS_METHOD, &br);

大节点的分页 (ContinuationPoint)

如果一个节点有 1000+ 个子节点, 单次 Browse 服务端可能截断. 此时 BrowseNode 返回的 BrowseResult 内含 ContinuationPoint, 用 _GetContinuationPoint 拿到后调 BrowseNext:

const uint8_t* cp = NULL;
int32_t cp_len = 0;
cp = DarraUa_BrowseResult_GetContinuationPoint(br, &cp_len);
if (cp && cp_len > 0) {
DarraUa_BrowseResult* next = NULL;
DarraUa_Session_BrowseNext(h, /*release*/ 0, cp, cp_len, &next);
/* ... 处理 next ... */
DarraUa_BrowseResult_Delete(next);
}

完整循环模板见 Browse 自动分页.


错误码

状态码含义
Good成功
BadNodeIdUnknownNodeId 不存在
BadNodeIdInvalidNodeId 字符串解析失败
BadCommunicationError网络故障

性能

  • 单次 Browse: ~5-15 ms
  • BrowseNodes 批量: 总耗时 ~ 单次 (省 N-1 次往返)
  • 1000+ 子节点会分页, 加 BrowseNext 处理

下一步