Dynamic variable declaration in a Function Block after the call of FB_Init

Joan M
2016-12-06
2016-12-30
  • Joan M - 2016-12-06

    Hello all,

    Is it possible to dynamically declare a variable after the FB_Init call?

    I'm thinking on a precompiled directive (PRAGMA) that would allow me to declare variables.

    Something like:

    CASE fb_type OF
      1:
          {define variable:ptr_toType1 : pointer to type1}
      2:
          {define variable:ptr_toType2 : pointer to type2}
    ...
    

    Now in the declaration area I'm using pragmas to declare pointers to types that actually exist, and I'm not declaring the ones that point to types that are not present in the project, but this keeps showing the unused/wrong pointers in the intellisense and I would like to avoid that as it is foreseen that this list will grow up fast.

    Thank you in advance!

     
  • rickj - 2016-12-08

    I'm thinking not possible as the compiler has run prior to execution of FB_Init.

     
  • Joan M - 2016-12-08

    Hi rjafrate,

    The best here would be being able to typecast a pointer easily, and to get the right intellisense from that typecast...

    Something like

    GetPointer()^.value := ...

    or

    (type)ptr^.value :=

    or similar...

    My class factory could return directly the right pointer using a Getter function...

    I'm using dynamic memory assignment initializing some pointers at runtime using __NEW and I'm only initializing the right ones. till here everything goes smooth.

    The problem is that I have to declare all the possible pointers as I have not seen a way to typecast a generic pointer.

    Moreover I can't get PVOID to work using SoMachine (Schneider). And I would like to avoid needing to know if the system is 32 or 64 bits capable.

    Having all the possible pointers declared makes it more difficult to use the intellisense and is more prone to errors at the coding stage.

    The original question comes for that reason...

    I'm using plenty of pragmas to declare only the pointers that point to existing function blocks, but even this reduces a lot the declared pointers, it still offers me much more possibilities than the right one (the one that has been initialized).

    So... undeclaring some of them (which wouldn't help at the intellisense stage).
    Declaring only the right ones (given the FB_Init...) here possibly you are right and it can't be done...
    Getting the pointer from a function and being able to dereference the return value to the right type and being able to use intellisense there... (that would be great).
    ...

    I can't think of more options... the last one would probably be the best one, but I have not seen how to do it...

    Thank you in advance for any pointer on the right direction... (bad joke...)

     
  • Anonymous - 2016-12-09

    Originally created by: scott_cunningham

    Maybe you can use the type cast functionality of interfaces. See "type cast" in the help or "__QUERYINTERFACE" function.

    Interfaces can extend the system interface and other interfaces. If you FBs (objects) implement many interfaces, then you can cast from one to another.

     
  • rickj - 2016-12-10

    Perhaps you could create a union of all possible pointer types and then just use the appropriate type. I haven't experimented so I don't know if this will make the auto-complete work the way you want or not.

     
  • josepmariarams - 2016-12-10

    There is not restrictions in Codesys in pointer casting. People of codesys uses pointer to dword as void*.

    For example if you want to see how the machine stores an lreal in binary format:

    A: lreal:=2.0
    B: pointer to ulint

    There is not restrictions on do:

    B:=adr(a).

    You can use a function which makes a __new and returns a pointer to dword. Is your responsability when you use it to pass to a usable pointer, which can be the pointer to a fb used in __new or a pointer which fb extends from.

     
  • Joan M - 2016-12-12

    First, thank you all who try to help.

    And a little more information about what I'm doing...

    I'm creating a library object that automatically creates some function blocks (parts) by parsing the parameters passed in the "constructor" FB_Init.
    Then I need to use those parts outside.

    Let's say fbA, fbB and fbC implement a specific interface ITFABC.
    I can dynamically create a new function block and get a pointer to the interface it implements, which of course allows me to work with any of those parts using the interface parameters. But this is not OK when I want to parameterize specific data for the instantiated function block fbA, fbB or fbC.

    Let's say fbA, fbB and fbC share three methods and some properties. But there are also some specific variables in each function block that are not in the interface.
    Clearly the interface will not allow me to access those out-of-the-interface specific variables.

    To solve that, at the same moment I'm creating the function block, I'm assigning a pointer to the newly created function block to ensure I'll be able to access all those input and specific variables said in another way: at this point, I would like to be able to use intellisense to assign values to members of the specific function block (the ones that are not in the interface).
    Let's say I do have pointers to each possible fb (fbA, fbB or fbC).
    Then I could do something like:

    FB_Init:
    if (type = A) THEN ptrA := ADR(fbA);
    elsif (type = B) THEN ptrB := ADR(fbB);
    else ptrC := ADR(fbC);
    end_if

    And then simply use ptrA^.special_variable_that_is_not_in_the_interface := 111; or ptrB^.special_variable_that_is_not_in_the_interface_neither := 222;...

    The problem with that is that even the right function block has been created at runtime, and only one pointer is correctly initialized, I still have plenty of pointers ptrA, ptrB and ptrC... one per each function block, and therefore the user of that library could use any of them giving wrong results if the used one is not the right one.

    I could even use a DWORD (or similar) to store the address, but even doing that, I would not be able to get the intellisense to cope gracefully... This is easy if the ptrA variable is a pointer to the right type, but it is not if it is only the DWORD (PVOID ideally) that holds the address.
    In order to be able to write ptrA^.value := yyy; I need to declare ptrA as a pointer to the right variable type. Therefore, I need to create a pointer to all the possible targets.
    This will allow the user to use ptrA, B, C... but only one of them will be initialized and the right one.
    Of course, the library user must know what is doing, but I'd prefer making things easier and avoid any possible confusion here.

    That is why I was proposing the following options:
    1. I'd love being able to declare variables at runtime and only create the needed pointers and then intellisense would offer only the right ones. (Not possible as this is not an interpreted language).
    2. I'd love being able to typecast after the creation (let's say I do have an address and I want to use it as a pointer to the right type). The problem I have here is that the user should know which pointer to use too, so even I’ve not seen how to do it this is neither a good solution.
    3. I'd love to be able to use a function that would return the pointer and then use it on the code like function()^.yyy := 111. This doesn’t look good too because that function would have to be implemented into the interface, and therefore, it should be specifically returning a kind of pointer in the same interface.
    4. Being able to hide some variables from the intellisense programmatically would allow me to simply hide the wrong pointers. (that has the drawback that I’d have to write all the variables everywhere).
    5. Being able to show a specific variable in the intellisense programmatically. That would be a great option given I could start hiding all the variables of a specific function block and then show only the right one.

    The idea is to be able to modify values of the newly created function blocks that are out of the main interface they implement using a pointer to the main function block.

    Or any other method that would allow me to do it.

    Thank you all!

     
  • camferti - 2016-12-30

    Make a call to different pou, and declare there the different variables

    case va1 of

    1: pou1(); ({define variable:ptr_toType1 : pointer to type1})
    2: pou2(); ({define variable:ptr_toType2 : pointer to type2})

    end_case

     Does this solve your problems?
    
     
  • Joan M - 2016-12-30

    Even that looks promising, I've tried this:

    {define variable:ptrE : pointer to fb_E}
    ptrE := __NEW(fb_E);
    

    Without luck, the compiler protests as ptrE is not defined and therefore a valid assignment target. Of course this differs on what you've told me as it is defined and used in the same POU.

    In order to be more strict to what you've proposed I've also created a brand new function block without anything inside, then I've written that code in it's main task:

    ]{define variable:ptrE : pointer to fb_E}
    

    Then I've instantiated that function block in one program and afterwards I've tried to use ptrE... it has not worked.

    Do you have a more elaborated example or recommendation?

    Of course, thank you in advance.

     

Log in to post a comment.