DataValue
darra::opcua::DataValue 包装一次 Read 返回的全部信息: 值 + 状态 + 时间戳. Move-only, 析构自动释放 native handle.
配套
- 内部值容器请看 Variant.
- 标准节点常量请看 WellKnownNodes.
公共属性 (访问器)
| 类别 | 属性 | 类型 | 访问 | 说明 |
|---|---|---|---|---|
| 值 | Value() | Variant | R | 实际值 (借用 owns=false, 由 DataValue 持有) |
StatusCode() | uint32_t | R | 数据质量, 原始 32-bit 码 | |
StatusEnum() | Status | R | 数据质量, 强类型枚举 (Good / Bad* / Uncertain*) | |
IsGood() | bool | R | 等价 StatusCode() == 0 | |
| 时间戳 (FileTime, 100ns since 1601) | SourceTimestamp() | int64_t | R | 数据源打的时间戳 |
ServerTimestamp() | int64_t | R | 服务端收到时打的时间戳 | |
| 底层 | Handle() | DarraUa_DataValue* | R | C 层句柄 (内部用) |
构造
通常由 SDK 内部构造 (从 s.Read / s.ReadHistory / s.ReadMany 返回). 用户也可以基于 native handle 包装用于 HistoryUpdate:
DataValue dv(native_handle, /*owns=*/true);
用法
auto dv = s.Read("ns=2;s=Temperature");
// 检查质量
if (!dv.IsGood()) {
std::cerr << "Bad value: 0x" << std::hex << dv.StatusCode() << "\n";
return;
}
// 取值
double temp = 0.0;
if (!dv.Value().TryGetDouble(temp)) {
std::cerr << "Type mismatch\n";
return;
}
// 时间戳 (FileTime → time_t)
constexpr int64_t WIN_EPOCH_OFFSET = 116444736000000000LL;
int64_t ft = dv.SourceTimestamp();
time_t t = (ft - WIN_EPOCH_OFFSET) / 10000000;
std::cout << "T = " << temp << " degC @ " << t << "\n";
Status 枚举重点值
| 值 | 含义 |
|---|---|
Status::Good (0x00000000) | 一切正常 |
Status::Uncertain (0x40000000) | 不确定但可用 |
Status::Bad (0x80000000) | 数据无效 |
Status::BadCommunicationError | 通讯失败 |
Status::BadNodeIdUnknown | 节点不存在 |
Status::BadNotReadable | 该 Attribute 不可读 |
业务代码必须检查 IsGood() 或显式比对枚举, 不能假设 Good.
时间戳含义
SourceTimestamp— 数据真实产生时间 (传感器采样时刻 / 计算时刻). 历史 / 趋势 / 同步用这个.ServerTimestamp— 服务端收到 / 处理时间. 用于诊断网络延迟. 一般不用于业务.
如果服务端没设 SourceTimestamp, 它就是 ServerTimestamp 的副本.
FileTime ↔ std::chrono 转换
constexpr int64_t WIN_EPOCH_OFFSET = 116444736000000000LL;
// FileTime → std::chrono::system_clock::time_point
auto FromFileTime(int64_t ft) {
return std::chrono::system_clock::time_point(
std::chrono::nanoseconds((ft - WIN_EPOCH_OFFSET) * 100));
}
// std::chrono::system_clock::time_point → FileTime
int64_t ToFileTime(std::chrono::system_clock::time_point tp) {
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
tp.time_since_epoch()).count();
return WIN_EPOCH_OFFSET + ns / 100;
}
内存所有权 (RAII)
DataValue 持有 native handle, 析构自动释放.
{
auto dv = s.Read("ns=2;s=T1");
// 用 dv ...
} // 离开作用域 dv 自动析构
// 批量
auto dvs = s.ReadMany(node_ids);
for (auto const& dv : dvs) {
// 用 dv (引用借用)
} // 离开作用域 dvs 整体析构, 内部 DataValue 逐个释放
注意 dv.Value() 返回的 Variant 是借用 owns=false, 生命周期跟 dv. dv 析构后再用 Variant 是 use-after-free:
auto dv = s.Read("ns=2;s=T1");
auto v = dv.Value(); // borrow
double d = 0; v.TryGetDouble(d);
// v 不能逃出 dv 的作用域