Ksouri Wissem
Ksouri Wissem

Reputation: 69

how to create pointer to function in codesys v3

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

Answers (5)

Alex
Alex

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

Special Guest
Special Guest

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

Quirzo
Quirzo

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.

Check this: https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/136447627.html&id=4296747249216071915

Upvotes: -1

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

mrsargent
mrsargent

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

Related Questions