Read / Write (C)
前置阅读
- 数据类型 Variant 与 DataValue 是所有读写的基础.
- 高频访问相同节点请用 RegisterNodes 加速.
- 实时变化通知用 Subscription 而不是循环 Read.
DarraUa_Session_ReadNode (单节点便捷)
DARRA_OPCUA_API DarraUa_DataValue* DARRA_OPCUA_CALL DarraUa_Session_ReadNode(
DarraUa_SessionHandle h,
const char* node_id_str,
DarraUa_AttributeId attribute,
DarraUa_Status* out_status);
| 参数 | 说明 |
|---|---|
node_id_str | NodeId 字符串 (i=2258 / ns=2;s=...) |
attribute | DARRA_UA_ATTR_VALUE (默认 13) / _DISPLAY_NAME / ... |
out_status | 出参, 写入服务级状态码 |
返回: DarraUa_DataValue* (失败为 NULL); 用 DarraUa_DataValue_Delete 释放.
DarraUa_Status st = 0;
DarraUa_DataValue* dv = DarraUa_Session_ReadNode(
h, "ns=2;s=Temperature", DARRA_UA_ATTR_VALUE, &st);
if (dv && DARRA_UA_STATUS_IS_GOOD(st)) {
const DarraUa_Variant* v = DarraUa_DataValue_GetValue(dv);
double temp = 0.0;
DarraUa_Variant_GetDouble(v, &temp);
printf("T = %.2f °C\n", temp);
DarraUa_DataValue_Delete(dv);
}
DarraUa_Session_ReadNodes (批量字符串 NodeId)
DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_ReadNodes(
DarraUa_SessionHandle h,
const char* const* node_id_strs,
const int32_t* attribute_ids, /* NULL = 全部默认 Value(13) */
uint32_t count,
DarraUa_DataValue** out_values); /* 调用方分配 count 个槽 */
out_values[i] 由 Stack 填充, 每个非 NULL 项要单独 DarraUa_DataValue_Delete. 单项失败 → out_values[i] = NULL, 不影响其他项, 顶层返回 Good.
const char* nodes[] = { "ns=2;s=T1", "ns=2;s=T2", "ns=2;s=T3" };
DarraUa_DataValue* dvs[3] = { NULL };
DarraUa_Status st = DarraUa_Session_ReadNodes(h, nodes, NULL, 3, dvs);
for (uint32_t i = 0; i < 3; ++i) {
if (dvs[i]) {
double v = 0.0;
DarraUa_Variant_GetDouble(DarraUa_DataValue_GetValue(dvs[i]), &v);
printf("%s = %g\n", nodes[i], v);
DarraUa_DataValue_Delete(dvs[i]);
}
}
DarraUa_Session_Read (批量结构体)
DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_Read(
DarraUa_SessionHandle h,
const DarraUa_ReadValueId* nodes,
uint32_t count,
DarraUa_DataValue** out_values);
DarraUa_ReadValueId:
typedef struct {
DarraUa_NodeId node_id;
DarraUa_AttributeId attribute_id;
const char* index_range; /* 可选 "0:9" 切数组; NULL = 全部 */
} DarraUa_ReadValueId;
适合任意 NodeId + AttributeId 组合:
DarraUa_ReadValueId items[] = {
{ /* 解析 "ns=2;s=T1" 得到的 NodeId */ ..., DARRA_UA_ATTR_VALUE, NULL },
{ ..., DARRA_UA_ATTR_DATA_TYPE, NULL },
};
DarraUa_DataValue* dvs[2] = { NULL };
DarraUa_Session_Read(h, items, 2, dvs);
/* ... 释放 ... */
实践中, 绝大多数场景用字符串版 _ReadNodes 即可, 结构体版仅在需要 IndexRange 切数组时使用.
DarraUa_Session_WriteNode (单节点便捷)
DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_WriteNode(
DarraUa_SessionHandle h,
const char* node_id_str,
DarraUa_AttributeId attribute,
const DarraUa_Variant* value);
| 返回 | 含义 |
|---|---|
DARRA_UA_STATUS_GOOD | 写入成功 |
DARRA_UA_STATUS_BAD_NOT_WRITABLE | 该 Attribute 不可写 |
DARRA_UA_STATUS_BAD_TYPE_MISMATCH | Variant 类型与节点 DataType 不符 |
DARRA_UA_STATUS_BAD_USER_ACCESS_DENIED | 无权限 |
Variant 由调用方维护, 函数不负责释放.
DarraUa_Variant* v = DarraUa_Variant_New();
DarraUa_Variant_SetDouble(v, 42.5);
DarraUa_Status st = DarraUa_Session_WriteNode(
h, "ns=2;s=Setpoint", DARRA_UA_ATTR_VALUE, v);
if (!DARRA_UA_STATUS_IS_GOOD(st))
fprintf(stderr, "Write failed: %s\n", DarraUa_StatusName(st));
DarraUa_Variant_Delete(v);
业务级失败不抛错 — 必须检查返回值
C 没有异常机制, 业务级失败统一通过 DarraUa_Status 返回值通知, 不要假定 Good.
DarraUa_Session_Write (批量)
DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_Write(
DarraUa_SessionHandle h,
const DarraUa_WriteValue* items,
uint32_t count,
DarraUa_Status* out_results); /* 调用方分配 count 个 */
DarraUa_WriteValue:
typedef struct {
DarraUa_NodeId node_id;
DarraUa_AttributeId attribute_id;
const char* index_range;
const DarraUa_Variant* value;
} DarraUa_WriteValue;
每项 status 写入 out_results[i], 顶层返回反映传输级状态.
Variant 构造速查
DarraUa_Variant* v = DarraUa_Variant_New();
DarraUa_Variant_SetBoolean(v, 1);
DarraUa_Variant_SetInt16(v, 42);
DarraUa_Variant_SetInt32(v, 42);
DarraUa_Variant_SetInt64(v, 42);
DarraUa_Variant_SetUInt32(v, 42);
DarraUa_Variant_SetFloat(v, 3.14f);
DarraUa_Variant_SetDouble(v, 3.14);
DarraUa_Variant_SetString(v, "hello");
DarraUa_Variant_SetDateTime(v, /* 100ns ticks since 1601 */ 0);
/* 数组 */
double arr[] = { 1.0, 2.0, 3.0 };
DarraUa_Variant_SetDoubleArray(v, arr, 3);
DarraUa_Variant_Delete(v);
完整清单见 Variant.
DataValue 字段速查
| Getter | 类型 | 说明 |
|---|---|---|
DarraUa_DataValue_GetValue(dv) | const DarraUa_Variant* | 实际值 (生命周期 = dv) |
DarraUa_DataValue_GetStatus(dv) | uint32_t | DataValue 自身的 StatusCode |
DarraUa_DataValue_GetSourceTimestamp(dv) | DarraUa_DateTime | 数据源时间戳 |
DarraUa_DataValue_GetServerTimestamp(dv) | DarraUa_DateTime | 服务端打的时间戳 |
uint32_t dv_status = DarraUa_DataValue_GetStatus(dv);
if (DARRA_UA_STATUS_IS_BAD(dv_status)) {
printf("Bad value: %s\n", DarraUa_StatusName(dv_status));
}
AttributeId 常用值
| Id | 名称 | 说明 |
|---|---|---|
| 1 | DARRA_UA_ATTR_NODE_ID | 节点 ID |
| 2 | DARRA_UA_ATTR_NODE_CLASS | 节点类别 |
| 3 | DARRA_UA_ATTR_BROWSE_NAME | 浏览名 |
| 4 | DARRA_UA_ATTR_DISPLAY_NAME | 显示名 |
| 5 | DARRA_UA_ATTR_DESCRIPTION | 描述 |
| 13 | DARRA_UA_ATTR_VALUE | 变量值 (默认) |
| 14 | DARRA_UA_ATTR_DATA_TYPE | 数据类型 NodeId |
| 17 | DARRA_UA_ATTR_ACCESS_LEVEL | 访问权限位 |
| 20 | DARRA_UA_ATTR_HISTORIZING | 是否在记录历史 |
| 21 | DARRA_UA_ATTR_EXECUTABLE | Method 是否可执行 |
最佳实践
- 批量优先: 监控 100+ Tag 用
_ReadNodes, 不要循环_ReadNode(省 N-1 次 RPC) - 必须 Delete DataValue: 漏 Delete 会泄漏 native 内存
- Write 检查返回值: 不要假定 Good
- 实时变化用订阅: 不要 1 秒一次轮询 Read, 改用
Subscription