튜토리얼에 method call이 있어 따라 해봤다. method를 서버에 설정하고, client에서 반응을 보고 싶었는데, 잘 안됬다. 두 시간 삽질만에 UA_VARINT에서 UA_String을 출력했다. 처음에는 몰랐는데 gdb로 구조를 보면 대략 알 수 있다. UA_String도 구조체라 data와 length로 구성된다. UA_Variant로 data를 출력하려면 UA_String으로 캐스팅하여 data의 data를 찾아야 한다.–;
(gdb)
45 /* Call a remote method */
46 UA_Variant input;
47 UA_String argString = UA_STRING("Hello Server");
48 UA_Variant_init(&input);
49 //UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
50 UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
51 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "input data is %s\n",(UA_String*)input.data);
52
53 size_t outputSize;
54 UA_Variant *output;
(gdb) display input
1: input = {type = 0xbefff4c8, storageType = (unknown: 3070066356), arrayLength = 0, data = 0xb6ffd13c, arrayDimensionsSize = 4,
arrayDimensions = 0xb6ffd14c}
(gdb) n
48 UA_Variant_init(&input);
1: input = {type = 0xbefff4c8, storageType = (unknown: 3070066356), arrayLength = 0, data = 0xb6ffd13c, arrayDimensionsSize = 4,
arrayDimensions = 0xb6ffd14c}
(gdb) print argString
$1 = {length = 12, data = 0x10f0c "Hello Server"}
(gdb) print argString->data
$2 = (UA_Byte *) 0x10f0c "Hello Server"
(gdb) n
50 UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
1: input = {type = 0x0, storageType = UA_VARIANT_DATA, arrayLength = 0, data = 0x0, arrayDimensionsSize = 0, arrayDimensions = 0x0}
(gdb) n
51 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "input data is %s\n",(UA_String*)input.data);
1: input = {type = 0x22250 <UA_TYPES+704>, storageType = UA_VARIANT_DATA, arrayLength = 0, data = 0x282d8, arrayDimensionsSize = 0, arrayDimensions = 0x0}
(gdb) print input->data
$3 = (void *) 0x282d8
(gdb) print input->data->data
Attempt to dereference a generic pointer.
(gdb) print (UA_String*)(input->data)->data
Attempt to dereference a generic pointer.
(gdb) print (UA_String*)(input.data)->data
Attempt to dereference a generic pointer.
(gdb) display argString
2: argString = {length = 12, data = 0x10f0c "Hello Server"}
(gdb) display
1: input = {type = 0x22250 <UA_TYPES+704>, storageType = UA_VARIANT_DATA, arrayLength = 0, data = 0x282d8, arrayDimensionsSize = 0, arrayDimensions = 0x0}
2: argString = {length = 12, data = 0x10f0c "Hello Server"}
(gdb) display &argString
3: &argString = (UA_String *) 0xbefff368
[2020-09-07 04:29:15.352 (UTC+0900)] info/userland input data is Hello Server�� Method call was successful, and 1 returned values available. [2020-09-07 04:29:15.352 (UTC+0900)] info/userland output data is Hello Hello Server [2020-09-07 04:29:15.353 (UTC+0900)] info/client Client Status: ChannelState: Closed, SessionState: Closed, ConnectStatus: Good
int main(void) {
UA_Client *client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
printf("retval is %d\n",retval);
if(retval != UA_STATUSCODE_GOOD) {
UA_Client_delete(client);
return (int)retval;
}
/* Read attribute */
UA_Int32 value2 = 0;
printf("\nReading the value of node (1, \"Test Var:Me\"):\n");
UA_Variant *val = UA_Variant_new();
retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "Test Var:Me"), val);
if(retval == UA_STATUSCODE_GOOD && UA_Variant_isScalar(val) &&
val->type == &UA_TYPES[UA_TYPES_INT32]) {
value2 = *(UA_Int32*)val->data;
//printf("the value is: %i\n", value2);
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,"myData is %d",value2);
}
//method call
#ifdef UA_ENABLE_METHODCALLS
/* Call a remote method */
UA_Variant input;
UA_String argString = UA_STRING("Hello Server");
UA_Variant_init(&input);
//UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "input data is %s\n",((UA_String*)input.data)->data);
size_t outputSize;
UA_Variant *output;
retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
if(retval == UA_STATUSCODE_GOOD) {
printf("Method call was successful, and %lu returned values available.\n",
(unsigned long)outputSize);
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "output data is %s\n",((UA_String*)output->data)->data);
UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
} else {
printf("Method call was unsuccessful, and %x returned values available.\n", retval);
}
UA_Variant_clear(&input);
#endif
UA_Variant_delete(val);
/* Clean up */
// UA_Variant_clear(&value);
UA_Variant_clear(&value2);
UA_Client_delete(client); /* Disconnects the client internally */
return EXIT_SUCCESS;
}