跳到主要内容

结构体解码

概述

OPC UA 1.04+ 把每个自定义结构体的字段定义放到 DataType 节点的 DataTypeDefinition 属性 (AttributeId=27, Part 5 §6.4.2)。SDK 实现完整协议层。

API

函数类别读写说明
DarraUa_StructDecoder_New(ua, &out_dec)构造绑定到会话
DarraUa_StructDecoder_Free(dec)释放析构
DarraUa_StructDecoder_Decode(dec, variant, &out_obj)方法解码 ExtensionObject
DarraUa_StructDecoder_DecodeBody(dec, body, n, type_id, &out_obj)方法直接给字节
DarraUa_StructDecoder_GetDefinition(dec, type_id, &out_def)方法获取 / 缓存
DarraUa_StructDecoder_PrefetchDefinitions(dec, ids, n)方法预热
DarraUa_DynamicObject_GetField(obj, name, &out_val)索引取字段 (DarraUa_FieldValue*)
DarraUa_DynamicObject_GetFields(obj, &out_kvs, &out_n)方法全字段 KV 列表
DarraUa_DynamicObject_Free(obj)释放释放

DarraUa_FieldValue 是 tagged union: type + value 联合体, type 枚举: BOOL / INT64 / UINT64 / FLOAT / DOUBLE / STRING / BYTES / DATETIME / NESTED / ARRAY / NULL_VALUE。

相关结构:

typedef enum {
SK_STRUCTURE = 0, // 普通
SK_STRUCTURE_WITH_SUBTYPED_VALUES = 1, // 含子类型
SK_STRUCTURE_WITH_OPTIONAL_FIELDS = 2, // 含可选 (前置 EncodingMask)
SK_UNION = 3, // Union (前置 selector)
SK_UNION_WITH_SUBTYPED_VALUES = 4 // Union + 子类型
} DarraUa_StructureKind;

代码示例

#include <opcua.h>

DarraUa_Session* ua;
DarraUa_Session_New("opc.tcp://localhost:4840", &ua);
DarraUa_Session_Connect(ua);

DarraUa_StructDecoder* dec;
DarraUa_StructDecoder_New(ua, &dec);

// 1) 读自定义结构
DarraUa_DataValue* dv = NULL;
DarraUa_Session_Read(ua, "ns=2;s=Robot.CurrentPose", ATTR_VALUE, &dv);

DarraUa_DynamicObject* pose = NULL;
DarraUa_StructDecoder_Decode(dec, &dv->value, &pose);

DarraUa_FieldValue* x_val = NULL;
DarraUa_DynamicObject_GetField(pose, "X", &x_val);
if (x_val && x_val->type == FV_DOUBLE)
printf("x = %f\n", x_val->value.dbl);

// 2) 嵌套
DarraUa_FieldValue* quat_val = NULL;
DarraUa_DynamicObject_GetField(pose, "Quaternion", &quat_val);
if (quat_val && quat_val->type == FV_NESTED) {
DarraUa_FieldValue* w_val = NULL;
DarraUa_DynamicObject_GetField(quat_val->value.nested, "W", &w_val);
if (w_val && w_val->type == FV_DOUBLE)
printf("qw = %f\n", w_val->value.dbl);
}

// 3) 全字段遍历
DarraUa_KvPair* fields = NULL;
size_t n_fields = 0;
DarraUa_DynamicObject_GetFields(pose, &fields, &n_fields);
for (size_t i = 0; i < n_fields; ++i)
printf("%s = ...\n", fields[i].key);
DarraUa_FreeKvPairs(fields, n_fields);

// 4) 预热
const char* ids[] = { "ns=2;i=3001", "ns=2;i=3002" };
DarraUa_StructDecoder_PrefetchDefinitions(dec, ids, 2);

DarraUa_DynamicObject_Free(pose);
DarraUa_FreeDataValue(dv);
DarraUa_StructDecoder_Free(dec);
DarraUa_Session_Free(ua);

实现限制

  • Native 层未导出 ExtensionObject 字节提取接口, Decode 在拿不到字节时返回 NULL_VALUE 占位字段
  • 协议层全部已实现, native 接通后 DecodeBody 立刻可用
  • DiagnosticInfo 跳过

最佳实践

  • 共享一个 decoder, 字段表缓存复用
  • PrefetchDefinitions 启动时调
  • 嵌套结构 type==NESTED 后访问
  • Union 看 definition.kind == SK_UNION

跨语言对照

C#PythonJavaC++RustC
StructDecoderStructDecoderStructDecoderStructDecoderStructDecoderDarraUa_StructDecoder
DecodedecodedecodeDecodedecodeDarraUa_StructDecoder_Decode
DynamicExtensionObjectDynamicExtensionObjectDynamicExtensionObjectDynamicExtensionObjectDynamicExtensionObjectDarraUa_DynamicObject

下一步