Beckhoff TC3 OPC UA Client Method Call

IGhoddan

Level-1
Beiträge
11
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
ich versuche seit einiger Zeit mit dem Beckhoff OPC UA Client eine Methode auf einem OPC UA Server aufzurufen. Dazu liefert Beckhoff auch ein Beispiel:

https://infosys.beckhoff.com/content/1031/tcopcuaserver/Resources/zip/4695964171.zip

Dieses Beispiel habe ich als Grundlage für meine Arbeit genommen. Die Methode, die ich versuche aufzurufen, hat einen "in" und drei "out" Parameter. Das Beispiel Programm habe ich entsprechend erweitert.
Mein Problem ist im Moment, dass der Methoden Aufruf den Fehler code liefert: 0xE4DD011B, UAC_E_CALLDECODE_FAILED. Dieser Fehler besagt, dass der Methoden Aufruf zwar erfolgreich war, aber die Rückgabe Parameter nicht decodiert werden konnten. Hat jemand hiermit schon Erfahrung gesammelt?

Danke

Ghoddan
 
Lass uns nicht dumm sterben.
Was sind deine 3 Ausgangsparameter (und eventuell der Eingangsparameter) und mit welchen Parametern rufst du den Baustein "UA_MethodCall" auf.
Irgend was ist nicht korrekt, aber ohne Infos kann man nichts dazu sagen.

Guga

P.S. prinzipiell nutze ich fast immer den Testclient von Unified Automation um zu schauen ob es prinzipiell geht. Hast du so was schon gemacht?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Guga,
ich will niemanden dumm sterben lassen ;). War mir nur nicht sicher, ob mir überhaupt jemand mit diesem Thema helfen kann, da ich dazu nichts im Forum gefunden hab. Daher habe ich erstmal die Frage allgemein gehalten..
Aber jetzt zum Punkt.. Du meinst den UaExpert von Unified Automation. Ja, mit dem habe ich die Methode schon erfolgreich aufgerufen. Ich habe übrigens auch schon den TCP Daten traffic analysiert wenn Beckhoff die Methode aufruft. Auf TCP Ebene kommen die Ergebnisse der Methode korrekt an, aber bei der decodierung in Beckhoff knallt es dann scheinbar (was sicherlich an meinem Programm liegt).
Es handelt sich um eine Methode eines MES Systems. Diese Methode liefert einen Error Text zu einem entsprechenden code zurück.
Im UaExpert sieht die Methode folgendermaßen aus:

97f8PrrgGz7BjvTYAAAAASUVORK5CYIIA



Wie müssen die Out- Parameter im Beckhoff Programm definiert sein, um diese Methode korrekt aufzurufen?

Danke.

Ghoddan
 
ich initialisiere die Variablen folgendermaßen:

bInputDataError := FALSE;
nOffset := 0;
MEMSET(ADR(InputArguments),0,SIZEOF(InputArguments));
MEMSET(ADR(nInputData),0,SIZEOF(nInputData));

nArg := 1;
(*numberIn1*) (********** Input parameter 1 **********)
InputArguments[nArg].DataType := eUAType_Int32;
InputArguments[nArg].ValueRank := -1; (* Scalar = -1 or Array *)
InputArguments[nArg].ArrayDimensions[1] := 0; (* Number of Dimension in case its an array *)
InputArguments[nArg].nLenData := SIZEOF(MAX_STRING_LENGTH); (* Length if its a STRING *)

//check if the size of input var is larger then the size of InputArgSize
IF nOffset + SIZEOF(errorCode) > nInputArgSize THEN
bInputDataError := TRUE;
RETURN;
ELSE
MEMCPY(ADR(nInputData)+nOffset,ADR(errorCode),SIZEOF(errorCode)); //copy the value in errorCode to nInputData
nOffset := nOffset + SIZEOF(errorCode); //set nOffset to errorCode
END_IF

cbWriteData := nOffset;

//prepare outputs

stOutputArgInfo[1].nLenData := SIZEOF(MAX_STRING_LENGTH);
stOutputArgInfo[2].nLenData := SIZEOF(MAX_STRING_LENGTH);
stOutputArgInfo[3].nLenData := SIZEOF(MAX_STRING_LENGTH);

stOutputArgInfo[1].DataType := E_UADataType.eUAType_String;
stOutputArgInfo[2].DataType := E_UADataType.eUAType_Int32;
stOutputArgInfo[3].DataType := E_UADataType.eUAType_String;

stOutputArgInfo[1].ValueRank := -1;
stOutputArgInfo[2].ValueRank := -1;
stOutputArgInfo[3].ValueRank := -1;

stOutputArgInfo[1].ArrayDimensions[1] := 0;
stOutputArgInfo[2].ArrayDimensions[1] := 0;
stOutputArgInfo[3].ArrayDimensions[1] := 0;

stOutputArgInfoAndData[1].nNumberOfOutputArguments := 1;
stOutputArgInfoAndData[2].nNumberOfOutputArguments := 1;
stOutputArgInfoAndData[3].nNumberOfOutputArguments := 1;

stOutputArgInfoAndData[1].stOutputArgInfo.ArrayDimensions[1] := 0;
stOutputArgInfoAndData[1].stOutputArgInfo.DataType := E_UADataType.eUAType_String;
stOutputArgInfoAndData[1].stOutputArgInfo.nLenData := SIZEOF(MAX_STRING_LENGTH);
stOutputArgInfoAndData[1].stOutputArgInfo.ValueRank:= -1;

stOutputArgInfoAndData[2].stOutputArgInfo.ArrayDimensions[1] := 0;
stOutputArgInfoAndData[2].stOutputArgInfo.DataType := E_UADataType.eUAType_Int32;
stOutputArgInfoAndData[2].stOutputArgInfo.nLenData := SIZEOF(MAX_STRING_LENGTH);
stOutputArgInfoAndData[2].stOutputArgInfo.ValueRank:= -1;

stOutputArgInfoAndData[3].stOutputArgInfo.ArrayDimensions[1] := 0;
stOutputArgInfoAndData[3].stOutputArgInfo.DataType := E_UADataType.eUAType_String;
stOutputArgInfoAndData[3].stOutputArgInfo.nLenData := SIZEOF(MAX_STRING_LENGTH);
stOutputArgInfoAndData[3].stOutputArgInfo.ValueRank:= -1;
 
Zuviel Werbung?
-> Hier kostenlos registrieren
so sieht das umgeschrieben Beispiel Programm aus:

PROGRAM PRG_METHOD_GetErrorText_1
VAR
(* Declarations for UA_Connect *)
fbUA_Connect: UA_Connect;
SessionConnectInfo: ST_UASessionConnectInfo;
nConnectionHdl: DWORD;

(* Declarations for UA_GetNamespaceIndex *)
fbUA_GetNamespaceIndex: UA_GetNamespaceIndex;
nNamespaceIndex: UINT;

(* Declarations for UA_MethodGetHandle *)
fbUA_MethodGetHandle: UA_MethodGetHandle;
ObjectNodeID: ST_UANodeID;
MethodNodeID: ST_UANodeID;
nMethodHdl: DWORD;

(* Declarations for UA_MethodCall *)
fbUA_MethodCall: UA_MethodCall;

sObjectNodeIdIdentifier : STRING(MAX_STRING_LENGTH) := 'G1_ID';
sMethodNodeIdIdentifier : STRING(MAX_STRING_LENGTH) := 'G1_getErrorText';

nAdrWriteData: PVOID;

//input
errorCode: DINT := -266; // change according to input value and data type
cbWriteData: DINT; // calculated automatically by M_Init()
InputArguments: ARRAY[1..1] OF ST_UAMethodArgInfo; // change according to input parameters
nInputData: ARRAY[1..4] OF BYTE;

//output
errorText: STRING(MAX_STRING_LENGTH);
returnCode: DINT;
customErrorString: STRING(MAX_STRING_LENGTH);


stOutputArgInfo: ARRAY[1..3] OF ST_UAMethodArgInfo; // change according to output parameters
stOutputArgInfoAndData: ARRAY [1..3] OF ST_OutputArgInfoAndData;
nOffset: DINT; // calculated by M_Init()
nArg: INT; // used by M_Init()

(* Declarations for UA_MethodReleaseHandle *)
fbUA_MethodReleaseHandle: UA_MethodReleaseHandle;

(* Declarations for UA_Disconnect *)
fbUA_Disconnect: UA_Disconnect;

(* Other Declarations *)
bTest: BOOL := TRUE;
bDone: BOOL;
bBusy: BOOL;
bError: BOOL;
nErrorID: DWORD;
iState: INT;
RTrig: R_TRIG;
bInputDataError: BOOL;
temp: INT;
END_VAR
VAR CONSTANT
nInputArgSize: INT := 4;
nNumberOfInputArguments: UDINT := 1; // change to number of input parameters
nNumberOfOutputArguments: UDINT := 3; // change to number of output parameters
END_VAR
 
in case 5 wird der eigentliche Methoden call gemacht. Alle vorherigen cases werden sauber durchlaufen ohne Fehler. Ich bekomme also einen gültigen Method Handle. Dann in case 5 passiert das hier:
yd7JqQTUvlcAAAAASUVORK5CYIIA
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hat ne Weile gedauert und aus tausend Gründen länger gedauert als ich dachte. Ich habe diesen Baustein im Vorfeld auch noch nie benutzt.
Schau mal nach Folgenden:

1): Deine Strukturdefinition ist logisch falsch aufgebaut. Du brauchst kein Array. Hier mein Beispiel für 2 Ausgangsparameter
TYPE ST_OutputArgInfoAndData :STRUCT
nNumberOfOutputArguments: UDINT; // determined amount of output parameters
nReserved: ARRAY[1..4] OF BYTE; // Reserved padding
stOutputArgInfo: ARRAY[1..2] OF ST_UAMethodArgInfo; // number of output parameters - M_Mul has 1 output parameter
pro: STRING;
ab: INT;
END_STRUCT
END_TYPE

2) Post #5: stOutputArgInfo[2].nLenData := SIZEOF(MAX_STRING_LENGTH); => du willst hier einen INT nutzen und keinen String.
die stOutputArgInfo[x].nLenData musst du akkurat setzen. Sonst gibt es eben deinen Fehler.


Guga

 
Zurück
Oben