How to initialize arrays of function blocks that need FB_Init to work

Joan M
2016-12-30
2020-08-21
  • Joan M - 2016-12-30

    Hello all,

    I've tried to search help files and Google, but it is clear that my Google Fu is not as good as needed now.

    I'm trying to put some function blocks inside an array.
    The problem with this super-easy task is that those function blocks use extensively the FB_Init function so I do need to initialize the parameters of those FB_Init functions at the array declaration and I don't know which syntax to use.

    Anyone here has done this and would like to share it?

    Thank you all!

    Happy new year to all the members here!

     
  • camferti - 2016-12-30

    Joan Murt hat geschrieben:
    Hello all,
    I've tried to search help files and Google, but it is clear that my Google Fu is not as good as needed now.
    I'm trying to put some function blocks inside an array.
    The problem with this super-easy task is that those function blocks use extensively the FB_Init function so I do need to initialize the parameters of those FB_Init functions at the array declaration and I don't know which syntax to use.
    Anyone here has done this and would like to share it?
    Thank you all!
    Happy new year to all the members here!

    l viewtopic.php?f=24&t=7438 l

     
  • Joan M - 2016-12-30

    Hello camferti,

    Sorry, but this is not working:

    fbE : ARRAY [1..4] OF fb_E:= [(ptrCF:=ADR(fb1CF)),(ptrCF:=ADR(fb2CF)),(ptrCF:=ADR(fb3CF)),(ptrCF:=ADR(fb4CF))];
    

    The FB_Init of fb_E looks like:

    METHOD FB_init : BOOL
    VAR_INPUT
       bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
       bInCopyCode : BOOL;  // if TRUE, the instance afterwards gets moved into the copy code (online change)
       
       ptrCF : POINTER TO fb_E := 0;
    END_VAR
    

    Of course I've also tried something like:

    fbE : ARRAY [1..4] OF fb_E:= [(bInitRetains :=TRUE,bInCopyCode :=TRUE,ptrCF:=ADR(fb1CF)),(bInitRetains :=TRUE,bInCopyCode :=TRUE,ptrCF:=ADR(fb2CF)),(bInitRetains :=TRUE,bInCopyCode :=TRUE,ptrCF:=ADR(fb3CF)),(bInitRetains :=TRUE,bInCopyCode :=TRUE,ptrCF:=ADR(fb4CF))];
    

    Same results...

    See that I'm trying to initialize the "constructor" (FB_Init) of the very same function block I'm instantiating...

    Thank you all!

     
  • josepmariarams - 2016-12-30

    I dont know if it could be that you need, but..

    I have made dynamic arraylist fb similar that it is in Java. You could instantiate the fbs outside arraylist and adding its to it.

     
  • Joan M - 2016-12-30

    Hi Josep M. Rams,

    If I understand you well you are proposing to create the function blocks as I'm doing now (outside of the array) and then add them into the array (an array of references or pointers to the same function blocks).

    This is what I'm doing now as it is a workaround to be able to put all the function blocks operations inside a loop if needed.

    This is a good option but I would prefer being able to make it at the declaration stage as then the job is done only once.

    Thank you for your proposal.

    And of course, bon any nou!

     
  • camferti - 2016-12-31

    I do not understand the purpose of all this, to be able to think a solution

    You declare a type

    TYPE POINT :
    STRUCT
    x:INT;
    y:INT;
    END_STRUCT
    END_TYPE

    Do you use the type
    VAR
    arr: ARRAY [0..10] OF POINT :=[(X:=0,Y:=0),(X:=250,Y:=50),(X:=1000,Y:=1000),(X:=1000,Y:=1000),(X:=1000,Y:=1000),(X:=1000,Y:=1000),(X:=1000,Y:=1000),(X:=1000,Y:=1000),(X:=1000,Y:=1000),(X:=1000,Y:=1000),(X:=1000,Y:=1000)];
    END_VAR

    Change data types and go
    good luck

     
  • Joan M - 2016-12-31

    @camferti

    First of all, thank you for answering.

    Then, the problem here is much more complex than what you are suggesting:

    I do need to create a function block (A) that configures itself at runtime.
    In order to do that I've created a Class Factory (which is another function block (CF) that using interfaces, pointers and the newly added in V3 DMA (dynamic memory assignment) creates the inner function blocks for A.
    This avoids the need to create each possible combination and it eases and reduces the code maintenance.

    In order to do that easily and avoiding having to code anything in the code area, I'm using the FB_Init (what a constructor would be for a class in normal OOP) function for both CF and A in order to be able to configure them.

    All this said, what you suggest is the initialization for a specific user defined type (a structure, ...) even this works, I don't need that.

    I do need to be able to initialize the specific FB_Init inside an array of CF at the declaration stage. And this is what I've not found how to achieve. Not documented in the Codesys, TwinCAT neither SoMM documentations, neither in the Google results I've found.

    what I'm using outside the aforementioned array is:

    fbCF    : fbClassFactory(1, 27, 3);
    fbA   : fbA(ADR(fbCF));
    

    As you can see here I'm passing parameters to the fb_Init function at declaration stage and I would like to be able to do the same in arrays.

    That's what I'm asking exactly here.

     
  • camferti - 2016-12-31

    Joan Murt hat geschrieben:
    @camferti
    First of all, thank you for answering.
    Then, the problem here is much more complex than what you are suggesting:
    I do need to create a function block (A) that configures itself at runtime.
    In order to do that I've created a Class Factory (which is another function block (CF) that using interfaces, pointers and the newly added in V3 DMA (dynamic memory assignment) creates the inner function blocks for A.
    This avoids the need to create each possible combination and it eases and reduces the code maintenance.
    In order to do that easily and avoiding having to code anything in the code area, I'm using the FB_Init (what a constructor would be for a class in normal OOP) function for both CF and A in order to be able to configure them.
    All this said, what you suggest is the initialization for a specific user defined type (a structure, ...) even this works, I don't need that.
    I do need to be able to initialize the specific FB_Init inside an array of CF at the declaration stage. And this is what I've not found how to achieve. Not documented in the Codesys, TwinCAT neither SoMM documentations, neither in the Google results I've found.
    what I'm using outside the aforementioned array is:

    fbCF    : fbClassFactory(1, 27, 3);
    fbA   : fbA(ADR(fbCF));
    

    As you can see here I'm passing parameters to the fb_Init function at declaration stage and I would like to be able to do the same in arrays.
    That's what I'm asking exactly here.

    So far as I can see the problem is the statement at run time?
    You can attach a small example of what you need?
    Next week, I will pass the query to the corresponding department

     
  • Joan M - 2016-12-31

    Hi again camferti,

    You can take a look at this other post here in the same forum... it shows exactly what I'm after:

    http://forum.codesys.com/viewtopic.php?t=5663

    There the proposed solution by scott_cunningham is to use a flag and at the code just initialize the values as desired.

    I'd love to do it at the declaration stage (as DavidWSteadman asks).

    I'm complicating it much more by using the class factory and all those things, but at the end the problem I'm trying to solve is that one.

    Thank you again!

     
  • camferti - 2016-12-31

    In the problem, which is MyObject?
    A variable ?. what type?
    A definite type?
    a function?
    Where declares the structure of MyObject?

    DavidWSteadman, Declare a function that refers to itself in the first step?

    Function x
    Var imput
    Arr array [0..1] of x;
    End_var

    This can not work

     
  • Joan M - 2016-12-31

    Hello again,

    Some extra explanations in the pictures comments.

    You can see three different ways to instantiate the MyObject function block in MyProgram.

    The first method of instantiation works well, but it forces me to create instances individually and I loose the possibility to put them inside an array. This is how I'm doing it right now.

    The second method doesn't work for me as I do need the FB_Init call which is not called/parameterized.

    The third one is what I'm interested in but doesn't work.

    Thank you for your time.

    IMG: MyObject.PNG

    IMG: MyObject.FB_Init.PNG

    IMG: MyProgram.PNG

     
  • camferti - 2016-12-31

    Joan Murt hat geschrieben:
    Hello again,
    Some extra explanations in the pictures comments.
    You can see three different ways to instantiate the MyObject function block in MyProgram.
    The first method of instantiation works well, but it forces me to create instances individually and I loose the possibility to put them inside an array. This is how I'm doing it right now.
    The second method doesn't work for me as I do need the FB_Init call which is not called/parameterized.
    The third one is what I'm interested in but doesn't work.
    Thank you for your time.

    Do you want to use a variable that you define within a function in the program?
    it's not possible.
    Why do you want to do that? I do not see the meaning. What are you trying to do?

    In the first line you make a call to the function "myObject (1)" so it does not give error
    In the second and third where you make the call to the function? You do not start the instance

    happy New Year

     
  • Joan M - 2016-12-31

    Hi again camferti...

    This is possible using the new Object Oriented Programming paradigm Codesys V.3 offers.

    FB_Init is not a "normal" function.
    It is the constructor function and it is used specifically to initialize internal things of the newly created function block. (Somehow configure it).
    this function is automatically called each time you instantiate the object that owns it (so each time you instantiate the fb that has it implemented).

    https://infosys.beckhoff.com/content/1033/tc3_plc_intro/9007199390945931.html?id=8333023073559976250

    As a good example, it works when used alone (first line) in the program:

    MyObjectAlone : MyObject(1);
    

    Here I'm not calling FB_Init at all, but it is automatically called and it receives 1 as the parameter ID.
    But it is not working when used in an array as I can't parameterize the FB_Init function...

    The reason of this to fail must be:

    A) The syntax I'm using is wrong (which is what I believe).
    B) The implementation of this feature is not done even the error message doesn't suggest this.

    In the newly attached picture you can see the errors the compiler show.

    Hope this clarifies a little bit more what happens here.

    Thank you very much.

    Again, happy new year.

    IMG: MyObject_Errors.PNG

     
  • rickj - 2017-01-04

    Joan if I understand correctly, perhaps you can do something like the following example. I haven't tried it so don't know if this approach works.

    // *** FB Definition
    FUNCTION_BLOCK MyObject
    VAR
       Id         : INT;
    END_VAR
    // *** Init Method
    METHOD FB_init : BOOL;
    VAR_INPUT
       bInitRetains   : BOOL;
       bInCodyCode   : BOOL;
       List         : POINTER TO ARRAY [0..32767] of MyObject;
       First         : INT;
       Last         : INT;
    END_VAR
    VAR
       i         : INT;
    END_VAR
    FOR i:=First TO Last BY 1 DO      // Search the list for self
       IF List^[i]=THIS^ THEN
          ID := i;
          Exit;
       END_IF
    END_FOR
    // *** Usage
    VAR
       ObjectArray   : ARRAY [1..4] of MyObject(List:=ADR(ObjectArray), First:=1, Last:=4);
    END_VAR
    
     
  • josepmariarams - 2017-01-05

    Dears.

    From your post I will test to pass parameters to FB_Init when the fB is created via __new and it works doing:

    tst:=__new(test_class(temp:=450));

    (Being temp an input of FB_init),

    After that I have test to do the same in arrays, but I only can pass the same parameter to all FB_inits of the array:

    tst2:ARRAY[0..2] of test_class(temp:=450);
    All tst2 elements are initialized with temp:=50.

    But in array initialization you could initialize internal FB variables:

    tst2:ARRAY[0..2] of test_class:=[(tt:=1),(tt:=2),(tt:=3)];

    Being tt internal variables of the FB not input variables of FB_init. That variables are setted after FB_init, but before a function with {'attribute call_after_init'}.

    You can use internal variables as constructor inputs and put the constructor code in a function with 'call_after_init' attribute.

     
  • Anonymous - 2017-01-06

    Originally created by: scott_cunningham

    I don't think your array initialization will ever work without a change from 3s. If you play around a bit, one of the precompile errors will be .

    To clarify... when you try to initialize your array, you are defining what your objects should literally , not how they should initialize. Take for example:

    MyArray : ARRAY[0..1] OF INT := [1, 2];
    

    You are telling the compiler you want your integers to integers 1 and then 2.

    If you do:

    MyArray : ARRAY[0..1] OF MyObject := [1, 2];
    

    You are telling the compiler that you want your MyObjects to integers 1 and then 2.

    This is not the same as having your object instantiate with a value of 1 and then 2. I doubt CoDeSys can do what you are hoping for.

    In fact, this works (unfortunately, the precompiler really wants me to use MyObject(0) - otherwise it complains I am not following the Fb_INIT):

    VAR
       Obj1 : MyObject(1);
       Obj2 : MyObject(2);
       MyArray : ARRAY[0..1] OF MyObject(0) := [Obj1, Obj2];
    END_VAR
    

    But this means your objects have to be created first and then put into the array (not what you wanted).

    If you are looking to simply have a unique ID with every instance, see this thread: l viewtopic.php?f=11&t=7348 l

    IMG: array_init.png

     
  • Anonymous - 2018-04-05

    Originally created by: Catharine Coombs

    https://explainjava.com/ They are written simple here, so it went out clear to me as to guys with no experience. But now I know for sure that CDS is not the very thing you need to try when you just have started practicing

     
  • yannickasselin1 - 2019-12-17

    @Joan M

    If anyone still looking for a way to achieve initialization of an array of objects through FB_Init, here's the syntax that worked for me:

    MyObjectArray: ARRAY[0..3] OF MyObject[(1), (2), (3), (4)];

    It is almost the same as Joan M tried in his exemple except that I have removed the " := " sign.

    Enjoy.

     
    👍
    1
  • robertklonek - 2020-04-24

    Hello,
    I was looking for this :-). Unfortunately, your yannickasselin1 method didn't work for me.
    I came up with a workaround - instead of FB_INIT I created a normal method: INIT (with the same implementation as FB_INIT). But since it's not called before running, I call them separately inside the FB_INIT method in another FB. For Example:

    MyObject
    METHOD init 
    VAR_IN_OUT
        ptrCF : ptrCF;
    END_VAR
    
    HelpObject
    METHOD FB_INIT
    FOR i := 0 TO 3 DO
        MyObjectArray[i].init(ptrCF[i]);
    END_FOR
    
    GLOBAL_VAR
         MyObjectArray: ARRAY[0..3] OF MyObject;
         ptrCF : ARRAY[0..3] OF ptrCF;
    END_VAR
    
     

    Last edit: robertklonek 2020-04-24
    • aikapan - 2020-08-21

      would also work for you! Why it should not? what's the problem?
      workaround is not clean code. try directly ;)

       

Log in to post a comment.