跳到主要内容

DataValue

darra::opcua::DataValue 包装一次 Read 返回的全部信息: 值 + 状态 + 时间戳. Move-only, 析构自动释放 native handle.

配套

公共属性 (访问器)

类别属性类型访问说明
Value()VariantR实际值 (借用 owns=false, 由 DataValue 持有)
StatusCode()uint32_tR数据质量, 原始 32-bit 码
StatusEnum()StatusR数据质量, 强类型枚举 (Good / Bad* / Uncertain*)
IsGood()boolR等价 StatusCode() == 0
时间戳 (FileTime, 100ns since 1601)SourceTimestamp()int64_tR数据源打的时间戳
ServerTimestamp()int64_tR服务端收到时打的时间戳
底层Handle()DarraUa_DataValue*RC 层句柄 (内部用)

构造

通常由 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 的作用域

下一步