OpcUaNode (C 中无对等体)
C# 提供 OpcUaNode 单节点包装, 通过属性触发 RPC (node.Value / node.DisplayName 等). C SDK 没有这种对象封装, 但可以用一次"批量多 Attribute 读"快速拿到节点完整信息.
前置阅读
- 入口请看 Nodes 总览.
- 想避免链式访问的多次 RPC 请看 TranslateBrowsePaths.
C# 写法 → C 写法对照
1. 读节点完整信息
// C# - 6 次 RPC
var n = ua.Nodes["ns=2;s=Temperature"];
Console.WriteLine(n.NodeId);
Console.WriteLine(n.DisplayName);
Console.WriteLine(n.BrowseName);
Console.WriteLine(n.NodeClass);
Console.WriteLine(n.DataType);
using var dv = n.Value;
C 推荐: 用 DarraUa_Session_Read 一次 RPC 读多个 Attribute (需要 ReadValueId 结构, 较繁琐), 或最简单地循环 _ReadNode:
/* C - 简单做法 */
struct { DarraUa_AttributeId attr; const char* name; } attrs[] = {
{ DARRA_UA_ATTR_DISPLAY_NAME, "DisplayName" },
{ DARRA_UA_ATTR_BROWSE_NAME, "BrowseName" },
{ DARRA_UA_ATTR_NODE_CLASS, "NodeClass" },
{ DARRA_UA_ATTR_DATA_TYPE, "DataType" },
{ DARRA_UA_ATTR_VALUE, "Value" },
};
for (int i = 0; i < (int)(sizeof(attrs)/sizeof(attrs[0])); ++i) {
DarraUa_Status st = 0;
DarraUa_DataValue* dv = DarraUa_Session_ReadNode(
h, "ns=2;s=Temperature", attrs[i].attr, &st);
if (dv) {
printf("%-12s = ...\n", attrs[i].name);
DarraUa_DataValue_Delete(dv);
}
}
更省 RPC 的做法用 DarraUa_Session_Read (单次, 5 个 ReadValueId), 见 Read / Write 批量结构体.
2. 写
// C#
ua.Nodes["ns=2;s=Setpoint"].Write(new Variant(25.5));
/* C */
DarraUa_Variant* v = DarraUa_Variant_New();
DarraUa_Variant_SetDouble(v, 25.5);
DarraUa_Session_WriteNode(h, "ns=2;s=Setpoint", DARRA_UA_ATTR_VALUE, v);
DarraUa_Variant_Delete(v);
3. 浏览子节点
// C#
foreach (var c in ua.Nodes["ns=2;s=Boiler1"].Children)
Console.WriteLine($" {c.BrowseName} -> {c.NodeId}");
/* C */
DarraUa_BrowseResult* br = NULL;
DarraUa_Session_BrowseNode(
h, "ns=2;s=Boiler1", DARRA_UA_NODE_CLASS_UNSPECIFIED, &br);
if (br) {
uint32_t n = DarraUa_BrowseResult_GetCount(br);
char buf[128];
for (uint32_t i = 0; i < n; ++i) {
const DarraUa_ReferenceDescription* rd =
DarraUa_BrowseResult_GetReference(br, i);
const char* name = DarraUa_Ref_GetBrowseName(rd);
DarraUa_Ref_GetNodeIdString(rd, buf, (int32_t)sizeof(buf));
printf(" %s -> %s\n", name ? name : "", buf);
}
DarraUa_BrowseResult_Delete(br);
}
链式访问的成本
// C# 方式 A: 链式索引器 - 4 次 RPC
using var time = ua.Nodes.Server["ServerStatus"]["CurrentTime"].Value;
// 1次 2次 3次 4次 Read
C 推荐:
/* 方式 B: 路径解析 - 2 次 RPC (Resolve + Read) */
char id[128];
DarraUa_Session_ResolveBrowsePath(
h, "i=2253", "/ServerStatus/CurrentTime", id, sizeof(id));
DarraUa_DataValue* dv = DarraUa_Session_ReadNode(
h, id, DARRA_UA_ATTR_VALUE, &st);
/* 方式 C: 直接用 NodeId - 1 次 RPC */
DarraUa_DataValue* dv = DarraUa_Session_ReadNode(
h, "i=2258", DARRA_UA_ATTR_VALUE, &st);
如果路径已知 → 方式 C; 探索式开发 → 方式 B.