Passing a NodeId as argument to a method

Questions regarding the use of the C++ SDK for Server or Client development or integration into customer products ...

Moderator: uasdkcpp

Post Reply
ArthurS
Full Member
Full Member
Posts: 6
Joined: 12 Oct 2022, 14:40

Passing a NodeId as argument to a method

Post by ArthurS »

I have a function that executes a method call for different methods. The input parameters are always passed as a string. I proceed as in the example project. This has worked so far.
Now a method has been added that expects a NodeId as input. In the example, the string is loaded into a UaVariant and then converted to the required type using changeType. However, more complex types are not supported.
So I created a UaNodeId using fromXmlString and assigned it to the UaVariant and then transferred it to the InputArgument using copyTo.
The subsequent call then returns the error BadInValidArgument. The method can be executed via the UaExpert. What have I done wrong?

Code: Select all

bool StringToUaVariant(LPCSTR _in, OpcUa_BuiltInType _type, UaVariant& _out, LPCSTR _logname)
{
	switch (_type) {
	case OpcUaType_Null:
	case OpcUaType_Guid:
	case OpcUaType_XmlElement:
	case OpcUaType_ExpandedNodeId:
	case OpcUaType_StatusCode:
	case OpcUaType_QualifiedName:
	case OpcUaType_ExtensionObject:
	case OpcUaType_DataValue:
	case OpcUaType_Variant:
	case OpcUaType_DiagnosticInfo:
		GLogPrintf(GLOG_OPCUA_ERR, "%s parameter type %u not supported", _logname, _type);
		break;
	case OpcUaType_NodeId:
		_out.setNodeId(UaNodeId::fromXmlString(_in));
		GLogPrintf(GLOG_OPCUA_SUB1, "%s parameter type NodeId set", _logname);
		return true;
	default:
	{
		_out.setString(_in);
		OpcUa_StatusCode status = _out.changeType(_type, OpcUa_False);
		if (!OpcUa_IsGood(status)) {
			if (_logname) {
				String msg = UaStringToString(UaStatus(status).toString());
				GLogPrintf(GLOG_OPCUA_ERR, "%s value failed - %s", _logname, msg.c_str());
			}
			return false;
		}
		return true;
	}
	}
	return false;
}

Code: Select all

		
			callRequest.inputArguments.create(inputArguments.length());
			for (OpcUa_UInt32 i = 0; i < inputArguments.length(); i++) {
				UaString argumentName(inputArguments[i].Name);
				String name = UaStringToString(argumentName);
				LPCSTR _value = jh.getStr(name.c_str());
				if (!_value) {
					args_ok = false;
					break;
				}

				UaVariant tempValue;
				// Try to change to built-in time, more complex types are not supported here
				if (!StringToUaVariant(_value, OpcUa_BuiltInType(inputArguments[i].DataType.Identifier.Numeric), tempValue,          	GetLogname().c_str())) {
					args_ok = false;
					break;
				}
				tempValue.copyTo(&callRequest.inputArguments[i]);
			}
		}

User avatar
Support Team
Hero Member
Hero Member
Posts: 3226
Joined: 18 Mar 2011, 15:09

Re: Passing a NodeId as argument to a method

Post by Support Team »

Hi,

generally your code look plausible, but
After converting the NodeId string to Variant you should check if the operation has succeeed.
> To be more explicite, you should check if the Variant really contains the NodeId value as it should.

Check the NodeId for NULL after creating the NodeId from xmlString.
Best regards
Unified Automation Support Team

ArthurS
Full Member
Full Member
Posts: 6
Joined: 12 Oct 2022, 14:40

Re: Passing a NodeId as argument to a method

Post by ArthurS »

This is what the definition of the argument looks like in the UAExpert:

Image

And this is how the call works in UAExpert:

Image

And this is an extract from a log file of my application:

Code: Select all

2025-02-03 16:08:05.143 [0x00001244] [Message  8] OPC_UA.0160-222033-001./Methods/Delete_Grob4Track call with arguments "{"ObjectToDelete":"ns=2;s=Sinumerik/FileSystem/ExtendedDrives/X204/_Grob4Track/MID_GM5129_01_01_CFG_cm_g4trace_x_axis_DAT_202306070206.xml"}"
2025-02-03 16:08:05.143 [0x00001244] [Message  8] OPC_UA.0160-222033-001./Methods/Delete_Grob4Track parameter type NodeId set
2025-02-03 16:08:05.143 [0x00001244] [Message  8] OPC_UA.0160-222033-001./Methods/Delete_Grob4Track input argument #0 Stringvalue: "ns=2;s=Sinumerik/FileSystem/ExtendedDrives/X204/_Grob4Track/MID_GM5129_01_01_CFG_cm_g4trace_x_axis_DAT_202306070206.xml"
2025-02-03 16:08:05.143 [0x00001244] [Message  8] OPC_UA.0160-222033-001./Methods/Delete_Grob4Track input argument #0 Type: 17
2025-02-03 16:08:05.143 [0x00001244] [Message  8] OPC_UA.0160-222033-001./Methods/Delete_Grob4Track request input argument #0 DataType: 17
2025-02-03 16:08:05.143 [0x00001244] [Message  8] OPC_UA.0160-222033-001./Methods/Delete_Grob4Track request input argument #0 ArrayType: 0
2025-02-03 16:08:05.143 [0x00001244] [Message  8] OPC_UA.0160-222033-001./Methods/Delete_Grob4Track request input argument #0 NamespaceIndex: 2
2025-02-03 16:08:05.143 [0x00001244] [Message  8] OPC_UA.0160-222033-001./Methods/Delete_Grob4Track request input argument #0 IdentifierType: 1
2025-02-03 16:08:05.143 [0x00001244] [Message  8] OPC_UA.0160-222033-001./Methods/Delete_Grob4Track request input argument #0 Identifier: Sinumerik/FileSystem/ExtendedDrives/X204/_Grob4Track/MID_GM5129_01_01_CFG_cm_g4trace_x_axis_DAT_202306070206.xml
The lines containing request argument show what I have after the conversion in callRequest.inputArguments[0]. Looks good to me. I still get BadInvalidArgument afterwards.

Post Reply