Updating H-file and C-file for function blocks with VAR_IN_OUT

This article is only relevant to you, if you have created C function blocks with →in-out variables (= VAR_IN_OUT variables) in a logi.CAD 3< version 3.1.0! If you have created such C functions blocks, you must update sections within the relevant H-file and/or the C-file as described in the following.

This article is not relevant, if:

  • your C function blocks do not contain in-out variables.

  • you have created just C functions.

  • you have created C function blocks with in-out variables in logi.CAD 3 version 3.1.0 (or later).

Reason for the update

The update is necessary because the C-code required for in-out variables (= VAR_IN_OUT) within a function block has changed in logi.CAD 3 version 3.1.0. In contrast to this: The C-code for in-out variables within a function has not changed.
Without the updated H-/C-files, an application using these function blocks cannot be built in logi.CAD 3 version 3.1.0 (or later). Instead, compiler errors are likely to occur.

Before you begin to update the files, create a backup of them. If you delete some code in the files by mistake, you can return to your original code.

The needed changes in a nutshell
  • Concerning the H-file: The code for VAR_IN_OUT variables is generated as it is generated for VAR_INPUT variables with REF_TO.
    This means that VAR_IN_OUT variables are listed as pointers within the instance data structure of the function block (as VAR_INPUT variables with REF_TO are). In previous versions, they had to be transferred directly with the call.

  • Concerning the C-file: When using a VAR_IN_OUT variable, write *(LC_this->LC_VD_in-out-variable) instead of (*LC_VD_in-out-variable).

If you need more information, examples illustrate the needed changes in detail:

images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/warning.svg If you are still unsure how to update your H-files and C-files, logi.cals recommends that you create an ST-object with a new name containing the required interface (as described under " Details: Creating a vendor block " ). When saving this ST-object containing the in-out variables, logi.CAD 3 generates the H-/C-file with the required implementation stubs. Then replace the code in your existing H-/C-files by the automatically generated code.

Example of updating the H-file

The following interface declares a function block with an in-out variable of data type INT.

Example for interface
{CustomImplementation}
FUNCTION_BLOCK MyFB_IO1
{ ImplementationProperties (functionHasCFile; ) }
VAR_IN_OUT
IO1 : INT;
END_VAR
VAR_OUTPUT
OUT1 : INT;
END_VAR
END_FUNCTION_BLOCK

The following lines are required within the H-file so that logi.CAD 3 can build the application in version 3.1.0 (or later). The lines /* ... */ are just comments that have been added to explain the structure.
images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/information.svg Observe that the order of variables in the H-file for vendor blocks is different from the order of variables in the H-file for ST/FBD objects. The required order for variables in a vendor function block is: VAR_INPUTVAR_IN_OUTENOVAR_OUTPUTVAR – auxiliary variables that are not visible to the user The order might become relevant when an application is updated by using the resource manager (= reloaded).

Example for updated H-file
#include <LC3CGBase.h>
 
/* type definition */
typedef struct _LC_TD_FunctionBlock_MYFB_IO1
{
LC_TD_INT (*LC_VD_IO1); /* NEW: pointer to VAR_IN_OUT variable */
LC_TD_BOOL LC_VD_ENO;
LC_TD_INT LC_VD_OUT1;
} LCCG_StructAttrib LC_TD_FunctionBlock_MYFB_IO1;
 
/* ColdBoot Initialization macro */
#define LC_INIT_FunctionBlock_MYFB_IO1(p) \
{ \
LC_INIT_PTR(&((p)->LC_VD_IO1)); \ /* NEW: initialization of pointer to VAR_IN_OUT variable */
LC_INIT_INT(&((p)->LC_VD_OUT1)); \
}
 
/* WarmBoot Initialization Macro */
#define LC_WINIT_FunctionBlock_MYFB_IO1(p,RF) \
{ \
LC_WINIT_PTR(&((p)->LC_VD_IO1),RF); \ /* NEW: initialization of pointer to VAR_IN_OUT variable */
LC_WINIT_INT(&((p)->LC_VD_OUT1),RF); \
}
 
/* implementation - Observe that the following line must be changed as well: The part 'LC_TD_INT (*LC_VD_IO1), ' is not needed here because of the new line in the type definition. */
void lcfu___MYFB_IO1(LC_TD_FunctionBlock_MYFB_IO1* LC_this, struct _lcoplck_epdb_1_impl* pEPDB);

Here is the content of the H-file required in logi.CAD 3 versions < 3.1.0:

Example for previous H-file
#include <LC3CGBase.h>
 
/* type definition */
typedef struct _LC_TD_FunctionBlock_MYFB_IO1
{
LC_TD_BOOL LC_VD_ENO;
LC_TD_INT LC_VD_OUT1;
} LCCG_StructAttrib LC_TD_FunctionBlock_MYFB_IO1;
/* ColdBoot Initialization Macro */
#define LC_INIT_FunctionBlock_MYFB_IO1(p) \
{ \
LC_INIT_INT(&((p)->LC_VD_OUT1)); \
}
 
/* WarmBoot Initialization Macro */
#define LC_WINIT_FunctionBlock_MYFB_IO1(p,RF) \
{ \
LC_WINIT_INT(&((p)->LC_VD_OUT1),RF); \
}
 
/* Implementation */
void lcfu___MYFB_IO1(LC_TD_FunctionBlock_MYFB_IO1* LC_this, LC_TD_INT (*LC_VD_IO1), struct _lcoplck_epdb_1_impl* pEPDB);

Example of updating the C-file when calling the vendor function block

The application is calling the specified vendor function block MyFB_IO1.

Example for interface
PROGRAM Test1
VAR
iMyFB_IO1 : MyFB_IO1;
Var1 : BOOL := TRUE;
Var2 : INT := 22;
Var3 : INT := 33;
Out1a, Out2a : INT;
Out1b, Out2b : INT;
END_VAR
iMyFB_IO1(EN:=TRUE, IO1:=Var2, IO1 => Out1a, OUT1 => Out1b);
iMyFB_IO1(EN:=Var1, IO1:=Var3, IO1 => Out2a, OUT1 => Out2b);
END_PROGRAM

images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/information.svg logi.CAD 3 automatically creates the C-file for Test1.
If you need to call such function blocks in your C-file, the following lines are required within the C-file in logi.CAD 3 version 3.1.0 (or later) because the pointer variables must be assigned in the instance data structure before the call.

Example for updated C-file (extract)
/* Programs */
void lcpu___TEST1(LC_TD_Program_TEST1* LC_this, struct _lcoplck_epdb_1_impl* pEPDB)
{
{
if ((LC_this->LC_VD_IMYFB_IO1.LC_VD_ENO = LC_EL_true) != LC_EL_false)
{
LC_this->LC_VD_IMYFB_IO1.LC_VD_IO1 = &LC_this->LC_VD_VAR2; // NEW LINE
lcfu___MYFB_IO1(&(LC_this->LC_VD_IMYFB_IO1), pEPDB); // CHANGED LINE
LC_this->LC_VD_OUT1A = LC_this->LC_VD_VAR2;
LC_this->LC_VD_OUT1B = LC_this->LC_VD_IMYFB_IO1.LC_VD_OUT1;
}
}
{
if ((LC_this->LC_VD_IMYFB_IO1.LC_VD_ENO = LC_this->LC_VD_VAR1) != LC_EL_false)
{
LC_this->LC_VD_IMYFB_IO1.LC_VD_IO1 = &LC_this->LC_VD_VAR3; // NEW LINE
lcfu___MYFB_IO1(&(LC_this->LC_VD_IMYFB_IO1), pEPDB); // CHANGED LINE
LC_this->LC_VD_OUT2A = LC_this->LC_VD_VAR3;
LC_this->LC_VD_OUT2B = LC_this->LC_VD_IMYFB_IO1.LC_VD_OUT1;
}
}
}

Here is the content of the C-file required in logi.CAD 3 versions < 3.1.0:

Example for previous C-file (extract)
/* Programs */
void lcpu___TEST1(LC_TD_Program_TEST1* LC_this, struct _lcoplck_epdb_1_impl* pEPDB)
{
{
if ((LC_this->LC_VD_IMYFB_IO1.LC_VD_ENO = LC_EL_true) != LC_EL_false)
{
lcfu___MYFB_IO1(&(LC_this->LC_VD_IMYFB_IO1), &LC_this->LC_VD_VAR2, pEPDB);
LC_this->LC_VD_OUT1A = LC_this->LC_VD_VAR2;
LC_this->LC_VD_OUT1B = LC_this->LC_VD_IMYFB_IO1.LC_VD_OUT1;
}
}
{
if ((LC_this->LC_VD_IMYFB_IO1.LC_VD_ENO = LC_this->LC_VD_VAR1) != LC_EL_false)
{
lcfu___MYFB_IO1(&(LC_this->LC_VD_IMYFB_IO1), &LC_this->LC_VD_VAR3, pEPDB);
LC_this->LC_VD_OUT2A = LC_this->LC_VD_VAR3;
LC_this->LC_VD_OUT2B = LC_this->LC_VD_IMYFB_IO1.LC_VD_OUT1;
}
}
}

Example of updating the C-file when assigning values to in-out variables

The following interface declares a function block with 2 in-out variables of data type INT.

Example for interface
{CustomImplementation}
FUNCTION_BLOCK fb_inoutvars
{ ImplementationProperties (functionHasCFile; ) }
VAR_IN_OUT
IO1 : INT;
IO2 : INT;
END_VAR
VAR
Var1 : INT;
END_VAR
END_FUNCTION_BLOCK

Within an ST-object, the following assignments would be possible (but not within the ST-object with {CustomImplementation}):

Example for intended ST-code
IO1 := 2;
Var1 := IO2;

If you need such assignments in your C-file, the following lines are required within the C-file in logi.CAD 3 version 3.1.0 (or later):

Example for updated C-file (extract)
*(LC_this->LC_VD_IO1) = (LC_TD_INT)2;
LC_this->LC_VD_VAR1 = *(LC_this->LC_VD_IO2);

This is necessary because the in-out variables are now pointers within the LC_this structure and must be dereferenced accordingly.

Here is the content of the C-file required in logi.CAD 3 versions < 3.1.0:

Example for previous C-file (extract)
(*LC_VD_IO1) = (LC_TD_INT)2;
LC_this->LC_VD_VAR1 = *(LC_VD_IO2);