Reputation: 69
Can you give me an example of how can I declare a pointer to function in my library? And how can I pass a pointer to function to my external library?
Upvotes: 5
Views: 6881
Reputation: 3
Hi I usually use a reference for this, it works the same as a pointer, but they behave like you are actually calling the method itself, if you for example want to reach this object via a pointer/reference, create the class
FUNCTION_BLOCK TButtonHandlers
//with
METHOD Click : BOOL
METHOD LongClick : BO
FUNCTION_BLOCK extendedButton EXTENDS TButtonHandlers
//with
METHOD Click : BOOL
METHOD LongClick : BO
In the class where you want to acces the object type
FUNCTION_BLOCK Manager
VAR_INPUT
Pointer_To_Object: REFERENCE TO TButtonHandlers;
Object1: TButtonHandlers;
Object2: extendedButton;
Extend: BOOL;
END_VAR
In a method (or directly in the FB) you can couple the reference using the following line of code:
IF Extend = FALSE THEN
Pointer_To_Object REF= Object1;//Original
ELSE
Pointer_To_Object REF= Object2;//Extended
END_IF
IF __ISVALIDREF(Pointer_To_Object)//Check if the reference is linked
Pointer_To_Object.Click();
END_IF
As you can see you are also able to link extended objects to the reference, giving you the chance to build polymorphic code.
The only downside of this method is that the reference only allows object that share the same parent class. If you want something that is more flexible , then I would recommend to use interfaces, If you want an example of such a code please let me know.
Upvotes: 0
Reputation: 11
This is an old topic, but seems there is another (much better) way to workaround the missing function pointer feature. I.e. using a pointer to a function block and calling its method, see below code.
FUNCTION_BLOCK TButtonHandlers
//with
METHOD Click : BOOL
METHOD LongClick : BOOL
and
PROGRAM FOO
VAR
Handlers: TButtonHandlers;
pHdl: POINTER TO TButtonHandlers;
END_VAR
-
pHdl:= ADR(Handlers); //Assign
pHdl^.Click(); //Function Call
Hope this helps people like me stumbling over this (old) topic.
Upvotes: 1
Reputation: 1425
Edit 09/2020: See the another answer in this topic and forget this one!
In Codesys based platforms it is possible to create a pointer to a data type or a function block. In TwinCAT 3 it is also possible to create a function pointer, but it can't be called in PLC program. The function pointer can only be given as a paramter to an external library component.
Upvotes: -1
Reputation: 98425
TL;DR: Totes possible and dead easy in CoDeSys v3.
In CoDeSys, "functions" are really function pointers stored in a function table.
In CodeSys v2, to take the address of a function you had to use INDEXOF(F_MyFunction)
, and this provided the index of the function pointer in the function table. Getting the address of the table was, uh, an exercise for the reader (it was possible to retrieve it with some gymnastics).
In CoDeSys v3, ADR
works instead of INDEXOF
, and thus ADR(F_MyFunction)
gives you the address of the function pointer that points to F_MyFunction
's code!
And guess what: you can set that function pointer, and F_MyFunction(...)
is just a call through that function pointer.
It's that simple.
So, to do indirect function calls, all you need to do is to declare a dummy "function" that in reality works like a settable function pointer!
Suppose we have two target functions that we want to call indirectly:
FUNCTION F_Add1: INT
VAR_INPUT
param : INT;
END_VAR
F_Add1:= param + 1;
END_FUNCTION
FUNCTION F_Add2: INT
VAR_INPUT
param : INT;
END_VAR
F_Add2:= param + 2;
END_FUNCTION
We then define a "function pointer" that must have the same signature as the indirectly called functions:
FUNCTION FPTR_Add : INT
VAR_INPUT
param : INT;
END_VAR
END_FUNCTION
We can also have a helper that assigns to function pointers:
F_FPTR_Assign
VAR_INPUT
dst : POINTER TO PVOID;
src : POINTER TO PVOID;
END_VAR
dst^ := src^;
END_FUNCTION
Finally, let's do some indirect calls:
// should return 3 if indirect calls work
FUNCTION F_Test : INT
VAR
val : INT;
END_VAR
F_FPTR_Assign(ADR(FPTR_Add), ADR(F_Add1));
// FPTR_Add points to F_Add1
val := FPTR_Add(val);
// here val has value 1
F_FPTR_Assign(ADR(FPTR_Add), ADR(F_Add2));
// FPTR_Add points to F_Add2
val := FPTR_Add(val);
// here val has value 3
F_Test := val;
END_FUNCTION
The only drawback of this method is that the debugger doesn't examine the dynamic values of function pointers and thus step into behaves like step over. The workaround is to set the breakpoint in the targeted functions, then both step into and step over will stop there.
There are other ways of achieving this effect, e.g. by direct manipulation of the stack frames, so even if this exact method would stop working due to some changes in CoDeSys, there are other ways of doing it.
Upvotes: 8
Reputation: 2442
Pointers are possible in codesys
.To create a pointer in codesys
you would do
VAR
pVar : POINTER TO BYTE;
tempVar : BYTE;
derefereceVar : BYTE;
END_VAR
//get a pointer to the byte variable
pVar := ADR(tempVar);
to dereference that pointer you would
derefereceVar := tempVar^;
So if you wanted to have a pointer as an argument to your function you would pass in pVar
or ADR(tempVar)
in the example above to a parameter of your function that takes a POINTER_TO_BYTE
as the type.
Upvotes: -1