Call (C)
API
DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_Call(
DarraUa_SessionHandle h,
const DarraUa_NodeId* object_id,
const DarraUa_NodeId* method_id,
const DarraUa_Variant* const* input_args,
uint32_t input_count,
DarraUa_Variant** out_args, /* 出参: Stack 分配 */
uint32_t* out_count,
DarraUa_Status* out_status); /* 出参: 方法业务状态 */
| 参数 | 说明 |
|---|---|
object_id | 方法所在 Object 节点 (DarraUa_NodeId 结构) |
method_id | 方法本身 NodeId |
input_args | 入参指针数组, 长度 = input_count |
out_args | 出参 Variant 数组指针 (*out_args 由 Stack malloc) |
out_count | 出参数量 |
out_status | 方法业务状态码 (传输 OK 但业务可能失败) |
| 返回 | 含义 |
|---|---|
DARRA_UA_STATUS_GOOD | 传输级 OK; 还要再判 *out_status |
DARRA_UA_STATUS_BAD_COMMUNICATION_ERROR | 网络故障 |
*out_status 是服务端返回的 Method 业务级码 (Good / BadMethodInvalid / BadInvalidArgument / BadUserAccessDenied / 业务自定义 Bad...).
内存所有权 (重要)
| 数据 | 释放 |
|---|---|
input_args[i] | 调用方持有, 调用结束后自行 DarraUa_Variant_Delete |
out_args (数组本身 + 每项) | DarraUa_VariantArray_Delete(out_args, out_count) (一次性) |
不要混用 free() (跨 DLL CRT 不一致).
完整示例
#include <darra_opcua/darra_opcua.h>
#include <stdio.h>
int main(int argc, char** argv)
{
const char* endpoint = (argc >= 2) ? argv[1] : "opc.tcp://localhost:4840";
DarraUa_Initialize();
/* ... Connect 略 ... */
DarraUa_SessionHandle h = /* ... */ 0;
/* 1. 解析 NodeId */
DarraUa_NodeId obj_id = { 0 }, mtd_id = { 0 };
DarraUa_NodeId_ParseString("ns=2;s=Calculator", &obj_id);
DarraUa_NodeId_ParseString("ns=2;s=Calculator.Add", &mtd_id);
/* 2. 入参 */
DarraUa_Variant* in0 = DarraUa_Variant_New();
DarraUa_Variant* in1 = DarraUa_Variant_New();
DarraUa_Variant_SetInt32(in0, 3);
DarraUa_Variant_SetInt32(in1, 4);
const DarraUa_Variant* inputs[2] = { in0, in1 };
/* 3. 调用 */
DarraUa_Variant* outs = NULL;
uint32_t out_n = 0;
DarraUa_Status method_st = 0;
DarraUa_Status st = DarraUa_Session_Call(
h, &obj_id, &mtd_id, inputs, 2, &outs, &out_n, &method_st);
if (!DARRA_UA_STATUS_IS_GOOD(st)) {
fprintf(stderr, "Transport error: %s\n", DarraUa_StatusName(st));
} else if (!DARRA_UA_STATUS_IS_GOOD(method_st)) {
fprintf(stderr, "Method error: %s\n", DarraUa_StatusName(method_st));
} else {
for (uint32_t i = 0; i < out_n; ++i) {
int32_t r = 0;
DarraUa_Variant_GetInt32(&outs[i], &r);
printf("sum = %d\n", (int)r);
}
}
/* 4. 释放出参 (整个数组) */
DarraUa_VariantArray_Delete(&outs, out_n);
/* 5. 释放入参 */
DarraUa_Variant_Delete(in0);
DarraUa_Variant_Delete(in1);
/* 6. 释放 NodeId 内部字符串 */
DarraUa_NodeId_ClearExport(&obj_id);
DarraUa_NodeId_ClearExport(&mtd_id);
DarraUa_Shutdown();
return 0;
}
错误码
| 状态码 | 含义 |
|---|---|
Good | 调用成功 |
BadNodeIdInvalid | NodeId 解析失败 |
BadCommunicationError | Transport 错 |
BadMethodInvalid | 该 NodeId 不是 Method |
BadInvalidArgument | 入参类型 / 个数不符 |
BadUserAccessDenied | 无权限调 |
业务级失败通过 *out_status 反映, 不通过顶层返回.
找方法的 NodeId
/* 1. Browse Object 子节点过滤 Method */
DarraUa_BrowseResult* br = NULL;
DarraUa_Session_BrowseNode(
h, "ns=2;s=Calculator",
DARRA_UA_NODE_CLASS_METHOD, &br);
uint32_t n = DarraUa_BrowseResult_GetCount(br);
char id_buf[128];
for (uint32_t i = 0; i < n; ++i) {
const DarraUa_ReferenceDescription* rd =
DarraUa_BrowseResult_GetReference(br, i);
DarraUa_Ref_GetNodeIdString(rd, id_buf, sizeof(id_buf));
printf(" %s -> %s\n", DarraUa_Ref_GetBrowseName(rd), id_buf);
}
DarraUa_BrowseResult_Delete(br);
/* 2. 看入参 / 出参签名 (Browse 该方法节点的 InputArguments / OutputArguments) */
DarraUa_Session_BrowseNode(
h, "ns=2;s=Calculator.Add",
DARRA_UA_NODE_CLASS_VARIABLE, &br);
/* InputArguments 是 Property, NodeClass=Variable, 值为 Argument[] 数组 */
输入参数构造
按方法签名构造 Variant:
/* Add(Int32, Int32) -> Int32 */
DarraUa_Variant* a = DarraUa_Variant_New(); DarraUa_Variant_SetInt32(a, 3);
DarraUa_Variant* b = DarraUa_Variant_New(); DarraUa_Variant_SetInt32(b, 4);
/* SetTemperature(string deviceId, double value) */
DarraUa_Variant* dev = DarraUa_Variant_New(); DarraUa_Variant_SetString(dev, "Boiler1");
DarraUa_Variant* val = DarraUa_Variant_New(); DarraUa_Variant_SetDouble(val, 85.5);
/* 数组参数 */
DarraUa_Variant* arr = DarraUa_Variant_New();
double points[] = { 1.0, 2.0, 3.0 };
DarraUa_Variant_SetDoubleArray(arr, points, 3);
/* 复杂结构 ExtensionObject — 高级用法, 后续版本完善 */
同步 / 异步
DarraUa_Session_Call 是同步阻塞调用, 内部走 RPC + 等响应. 异步在后续版本提供. 上层若想异步, 用线程池调度.