跳到主要内容

Call (C)

前置 / 配套
  • 数据类型 Variant 是入参 / 出参的容器.
  • 找方法 NodeId 用 Browsefilter = DARRA_UA_NODE_CLASS_METHOD.

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调用成功
BadNodeIdInvalidNodeId 解析失败
BadCommunicationErrorTransport 错
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 + 等响应. 异步在后续版本提供. 上层若想异步, 用线程池调度.

下一步