Open Core Interface - MLPI
MLPI-MotionLogicProgrammingInterface(mlpi4LabVIEW)  1.26.2
Extension of PLC functions by C/C++ implementation
Collaboration diagram for Extension of PLC functions by C/C++ implementation:

Functions

MLPIRESULT mlpiLogicPouExtensionRegister (const MLPIHANDLE connection, const WCHAR16 *name, const MLPIPOUFNCPTR function, const ULONG signature=0, const ULONG version=0)
 
MLPIRESULT mlpiLogicPouExtensionUnregister (const MLPIHANDLE connection, const WCHAR16 *name, const MLPIPOUFNCPTR function, const ULONG signature=0, const ULONG version=0)
 
MLPIRESULT mlpiLogicPouExtensionUnregisterAll (const MLPIHANDLE connection)
 

Detailed Description

The following functions provide the possibility of using customized C/C++ extension within the IEC61131-3 environment IndraWorks / IndraLogic.

Note
This functions can only be used within a real-time application on the target and there only within the kernel space! This functions is not available in other toolboxes!

With these functions, you can integrate your customized C/C++ functionality into the IEC61131-3 environment IndraWorks / IndraLogic as a IEC 61131-3 function, function block, method or property. The C/C++ functions must be implemented in a user-defined real-time extension. For more information about customized, a user-defined real-time extension and the Bosch Rexroth Workbench OEM ; please refer to the respective documents (Notes for LabVIEW users).

Function Documentation

MLPIRESULT mlpiLogicPouExtensionRegister ( const MLPIHANDLE  connection,
const WCHAR16 name,
const MLPIPOUFNCPTR  function,
const ULONG  signature = 0,
const ULONG  version = 0 
)

This function registers a C/C++ implementation of a POU (e.g. function block) from the MLPI real-time environment. The registration enables the possibility to call the C/C++ implementation by a related POU declared in an IEC 61131-3 environment IndraWorks. This means, you can call POUs from PLC which are coded in C/C++.

Note
This function can only be used within a real-time application on the target and there only within the kernel space! This function is not available in other toolboxes!
Parameters
[in]connectionHandle for multiple connections.
[in]nameName of POU in the IEC 61131 environment.
[in]functionFunction pointer to C/C++ implementation.
[in]signatureSignature of POU interface (reserved).
[in]versionVersion of POU library if implemented within a library.
Returns
Return value indicating success (>=0) or error (<0).
Note
The name of POUs declared in the IEC 61131-3 environment IndraWorks share a single namespace so use your own prefix (e.g. your project name) to avoid collisions!
The signature of POU is a checksum of their interface. Disable this check by setting it to zero (default).
The versions of POUs are taken from the library where they are implemented. The value results from the four elements of the library version ("aa.bb.cc.dd" -> 0xaabbccdd). When not used within a library this value is set to zero (default).
Attention
The memory layout of all C/C++ structs which are mapped to IEC POUs, as described below, needs to follow 'natural alignment'! This is because the IEC compiler aligns the memory of elements and variables given by the POUs to addresses which are multiples of its own size. You may want to use padding bytes in your structs or compiler dependent pragmas to make your C/C++ structs to match with the IEC memory layout or use the provided MLPI IEC data types (like MLPI_IEC_LREAL, MLPI_IEC_USINT, ... see mlpiGlobal.h)
Note
The declaration of an IEC variable of type STRING without any length notation cause an implicit allocation of 80+1 characters so in this case you have to declare an array of 81 elements of MLPI_IEC_STRING within your C/C++ application. The declaration of an IEC variable of type STRING with length n cause an allocation of n+1 characters so in this case you have to declare an array of n+1 elements of MLPI_IEC_STRING within your C/C++ application. The same applies to the type WSTRING and the corresponding MLPI_IEC_WSTRING.
Example "IEC function":

To use a C/C++ implementation within the IEC 61131 environment IndraWorks as a function you need to do the following:

  • Declare an external POU as a function with a proper interface within IndraWorks.
    • Add a POU "<function_name>" (e.g. 'SimpleCalc') as a function.
      ExtIecFncSimpleCalc_Add.png
      Adding new POU 'SimpleCalc' as function.

    • Declare the interface of inputs and outputs of the function. You do not need to implement any code.
      1 FUNCTION SimpleCalc : LREAL
      2 VAR_INPUT
      3  in1: LREAL;
      4  in2: LREAL;
      5 END_VAR
      6 VAR
      7 END_VAR
      ExtIecFncSimpleCalc_Decl.png
      Declaration of interface of IEC function.

    • Enable the build property "External implementation" (late link in the runtime) of POU. You will find this build property on right click of POU within the project tree ("Property...->Build").
      ExtIecFncSimpleCalc_ExtImpl.png
      Build property: External Implementation.

  • Declare a corresponding interface within a C/C++ file and implement the runtime code needed.
    • Declare a structure "<function_name>_struct" with the elements of the IEC function in following order:
      • All input variables (VAR_INPUT) and all in-out variables (VAR_IN_OUT) in order defined in IEC.
      • All output variables (VAR_OUTPUT) in order defined in IEC.
      • The implicit function output comes last.
      1 #include "mlpiLogicLib.h"
      2 
      3 typedef struct SimpleCalc_struct
      4 {
      5  MLPI_IEC_LREAL in1; // Declaration of input
      6  MLPI_IEC_LREAL in2; // Declaration of input
      7  MLPI_IEC_LREAL out; // Declaration of implicit function output
      8 }SimpleCalc_struct;
    • Declare a C/C++ function "<function_name>" with the following interface and implement the desired functionality.
      • The return type of the function is void.
      • The function has exactly one parameter of type pointer to "<function_name>_struct".
      1 void SimpleCalc(SimpleCalc_struct *instance)
      2 {
      3  // Implementation of functionality
      4  instance->out = instance->in1 + instance->in2;
      5  return;
      6 }

  • Finally register the C/C++ implementation within the runtime to enable call of function "<function_name>" within a PLC application. The registered name of the C/C++ function must match the name of the IEC function. The name of the C/C++ function freely selectable and can be different.
    1 WCHAR16 name[MLPI_APPLICATION_MAX_LENGTH_OF_POU_NAME] = L"SimpleCalc";
    2 MLPIPOUFNCPTR function = (MLPIPOUFNCPTR) SimpleCalc;
    3 MLPIRESULT result = mlpiLogicPouExtensionRegister(connection, name, function);

  • After the external function has been registered, you can download your PLC program and use the function.
Example "IEC function block":

A function block corresponds to at least one implicit method called "__Main". A function block can be extended by a composition of several methods and properties. Additional predefined methods are "FB_Init", "FB_Exit" and "FB_Reinit". These initialization and exit methods have a fixed interface and fixed variable names and will be called automatically in predefined situations. The inputs of the predefined methods will be set by the runtime to mark the situation exactly. Furthermore, a customer can add any further method or property. Each method or property can be implemented independently in the IEC 61131 environment IndraWorks respectively in the C/C++ environment.

The predefined methods "FB_Init", "FB_Exit" and "FB_Reinit" are called on following situations:
Action FB_Exit FB_Init FB_Reinit Shown in diagram...
bInCopyCode bInCopyCode bInitRetains
Start, Stop 'base actions'
Single cycle 'other actions'
Download, Boot up FALSE TRUE 'base actions'
Download new FALSE FALSE TRUE 'other actions'
Reset warm FALSE FALSE FALSE 'reset actions ...'
Reset cold FALSE FALSE TRUE 'reset actions ...'
Reset origin FALSE 'reset actions ...'
Online change, w/o 'online change actions ...'
Online change, new FALSE FALSE 'online change actions ...'
Online change, delete FALSE 'online change actions ...'
Online change, move TRUE TRUE FALSE called 'online change actions ...'
Remarks
If you allocate resp. new objects within FB_Init you have to free resp. delete it on FB_Exit except on action "Online Change, move', which will be recognized through 'bInCopyCode == TRUE'.
Note
Used enumeration values on transition notes are short forms of MlpiApplicationEvent meaning e.g. 'STOP_INIT' is equal to 'MLPI_APPLICATIONEVENT_STOP_INIT'. The event 'OP_STATE_CHANGE' resp. 'MLPI_APPLICATIONEVENT_OP_STATE_CHANGE' could be called in series (multiple) without further notice. The method '__main' resp. "__Main" could be called in series (multiple) without further notice.
PouStateDiagram_base_action.png
Call of predefined methods in context of 'base actions'


PouStateDiagram_reset_actions_RUN.png
Call of predefined methods in context of 'reset action on RUN'


PouStateDiagram_reset_actions_STOP.png
Call of predefined methods in context of 'reset actions on STOP'


PouStateDiagram_online_change_actions_RUN.png
Call of predefined methods in context of 'online change actions on RUN'


PouStateDiagram_online_change_actions_STOP.png
Call of predefined methods in context of 'online change actions on STOP'


PouStateDiagram_other_action.png
Call of predefined methods in context of 'other actions'



To use a C/C++ implementation within the IEC 61131 environment IndraWorks as a function block you need to do the following:

  • Declare an external POU (function block) with a proper interface within IndraWorks.
    • Add a POU "<functionblock_name>" (e.g. 'SimpleCalc') as a function block .
      ExtIecFbSimpleCalc_Add.png
      Adding new POU 'SimpleCalc' as a function block.

    • Declare the interface of inputs, outputs and local variables of the function block. You need not implement any IEC code.
      1 FUNCTION_BLOCK SimpleCalc
      2 VAR_INPUT
      3  in1: LREAL;
      4  in2: LREAL;
      5 END_VAR
      6 VAR_OUTPUT
      7  out: LREAL;
      8 END_VAR
      9 VAR
      10 END_VAR
      ExtIecFbSimpleCalc_Decl.png
      Declaration of interface of IEC function block.

    • Enable the build property "External implementation" (late link in the runtime) of POU. You will find the build property on right click on POU within the project tree ("Property...->Build").
      ExtIecFbSimpleCalc_ExtImpl.png
      Build property: External Implementation.

    • According to your requirements, add the predefined methods FB_Init, FB_Exit and / or FB_Reinit and your further methods and properties and declare the interface of each POU. You also need not implement any code.
      1 METHOD FB_Init : BOOL
      2 VAR_INPUT
      3  bInitRetains: BOOL;
      4  bInCopyCode: BOOL;
      5 END_VAR
      ExtIecFbSimpleCalc_DeclInit.png
      Declaration of interface of INIT method of IEC function block.

      1 METHOD FB_Reinit : BOOL
      2 VAR_INPUT
      3 END_VAR
      ExtIecFbSimpleCalc_DeclReinit.png
      Declaration of interface of REINIT method of IEC function block.

      1 METHOD FB_Exit : BOOL
      2 VAR_INPUT
      3  bInCopyCode: BOOL;
      4 END_VAR
      ExtIecFbSimpleCalc_DeclExit.png
      Declaration of interface of EXIT method of IEC function block.

    • Enable the build property "External implementation" (late link in the runtime) of all desired POUs.

  • Declare the corresponding interfaces within a C/C++ file.
    • The instance of a function block contains all function block variables in the declared order plus a pointer to the virtual function table at first. Declare an instance structure "<functionblock_name>_struct" with the elements of the IEC function block. Please note that the structure of the instance is solely determined by the order of the declaration, rather than through affiliation with an input, output or local. If the outputs and inputs were interchanged in the IEC declaration, they would also have to be interchanged in your C/C++ environment. This example uses the MLPI IEC data types like MLPI_IEC_LREAL (see mlpiGlobal.h) for a valid alignment. The declaration of your instance must match the following criteria:
      • At first a virtual function pointer.
      • All variables in the order defined in IEC function block.
      • All implicit local property variables in case of using of properties, named like the resp. properties.
      1 typedef struct SimpleCalc_struct
      2 {
      3  void* __VFTABLEPOINTER; // Declaration of virtual function pointer
      4  MLPI_IEC_LREAL in1; // Declaration of function block input
      5  MLPI_IEC_LREAL in2; // Declaration of function block input
      6  MLPI_IEC_LREAL out; // Declaration of function block output
      7  MLPI_IEC_LREAL userPropVar; // Implicit local property variable
      8 }SimpleCalc_struct;
    • Alternatively the structure can be declared with proper alignment dummies.
      1 typedef struct SimpleCalc_struct
      2 {
      3  void* __VFTABLEPOINTER; // Declaration of virtual function pointer
      4  ULONG alignment; // Alignment dummy
      5  DOUBLE in1; // Declaration of function block input
      6  DOUBLE in2; // Declaration of function block input
      7  DOUBLE out; // Declaration of function block output
      8  DOUBLE userPropVar; // Implicit local property variable
      9 }SimpleCalc_struct;
    • Declare a structure "<functionblock_name>_Main_struct" with a pointer to the instance structure "<functionblock_name>_struct".
      1 typedef struct SimpleCalc_Main_struct
      2 {
      3  SimpleCalc_struct *instance; // Declaration of instance pointer
      4 }SimpleCalc_Main_struct;
    • In addition, declare all needed method structures like in the following examples "<functionblock_name>_<method_name>_struct". All methods first have to implement a pointer to the instance structure. These examples use the MLPI IEC data types like MLPI_IEC_BOOL (see mlpiGlobal.h) for valid alignments, but in this case, there are no matters if using BOOL8.
      1 typedef struct SimpleCalc_FB_Init_struct
      2 {
      3  SimpleCalc_struct *instance; // Declaration of instance pointer
      4  MLPI_IEC_BOOL bInitRetains; // Declaration of predefined method input (no matter if using BOOL8)
      5  MLPI_IEC_BOOL bInCopyCode; // Declaration of predefined method input (no matter if using BOOL8)
      6  MLPI_IEC_BOOL FB_Init; // Declaration of implicit method output (no matter if using BOOL8)
      7 }SimpleCalc_FB_Init_struct;
      1 typedef struct SimpleCalc_FB_Reinit_struct
      2 {
      3  SimpleCalc_struct *instance; // Declaration of instance pointer
      4  MLPI_IEC_BOOL FB_Reinit; // Declaration of implicit method output (no matter if using BOOL8)
      5 }SimpleCalc_FB_Reinit_struct;
      1 typedef struct SimpleCalc_FB_Exit_struct
      2 {
      3  SimpleCalc_struct *instance; // Declaration of instance pointer
      4  MLPI_IEC_BOOL bInCopyCode; // Declaration of predefined method input (no matter if using BOOL8)
      5  MLPI_IEC_BOOL FB_Exit; // Declaration of implicit method output (no matter if using BOOL8)
      6 }SimpleCalc_FB_Exit_struct;
    • If desired, you have to declare properties like in the following examples "<functionblock_name>_set<property_name>_struct" resp. "<functionblock_name>_get<property_name>_struct". A property also has to implement a pointer to the instance structure. A property implements an implicit local variable within the instance of the POU. This example uses the MLPI IEC data types like MLPI_IEC_LREAL (see mlpiGlobal.h) for a valid alignment.
      1 typedef struct SimpleCalc_setUserPropVar_struct
      2 {
      3  SimpleCalc_struct *instance; // Declaration of instance pointer
      4  MLPI_IEC_LREAL setUserPropVar; // Declaration of setter input
      5  MLPI_IEC_BOOL __setUserPropVar; // Declaration implicit property output
      6 }SimpleCalc_setUserPropVar_struct;
      1 typedef struct SimpleCalc_getUserPropVar_struct
      2 {
      3  SimpleCalc_struct *instance; // Declaration of instance pointer
      4  MLPI_IEC_LREAL __getUserPropVar; // Declaration of implicit getter output
      5 }SimpleCalc_getUserPropVar_struct;
    • Alternatively the setter and getter can be declared with proper alignment dummies.
      1 typedef struct SimpleCalc_setUserPropVar_struct
      2 {
      3  SimpleCalc_struct *instance; // Declaration of instance pointer
      4  ULONG alignment; // Alignment dummy
      5  DOUBLE setUserPropVar; // Declaration of setter input
      6  BOOL8 __setUserPropVar; // Declaration implicit property output (status)
      7 }SimpleCalc_setUserPropVar_struct;
      1 typedef struct SimpleCalc_getUserPropVar_struct
      2 {
      3  SimpleCalc_struct *instance; // Declaration of instance pointer
      4  ULONG alignment; // Alignment dummy
      5  DOUBLE __getUserPropVar; // Declaration of implicit getter output
      6 }SimpleCalc_getUserPropVar_struct;
    • Implement the required functionalities of "<function_name>__Main", "<function_name>__FB_Init", "<function_name>__FB_Reinit", "<function_name>__FB_Exit", ..., "<function_name>__<method_name>", "<function_name>__set<property_name>" and "<function_name>__get<property_name>".
      • The return type of each function is void.
      • Each function has exactly one parameter of type pointer to the respective structure.
      1 #include "mlpiLogicLib.h"
      2 
      3 void SimpleCalc__Main(SimpleCalc_Main_struct *p)
      4 {
      5  SimpleCalc_struct *instance = (SimpleCalc_struct*) p->instance;
      6 
      7  // Implementation of functionality
      8  instance->out = instance->in1 + instance->in2;
      9  return;
      10 }
      1 void SimpleCalc__FB_Init(SimpleCalc_FB_Init_struct *p)
      2 {
      3  SimpleCalc_struct *instance = (SimpleCalc_struct*) p->instance;
      4 
      5  // Implementation of functionality
      6  if( (p->bInitRetains==TRUE) && (p->bInCopyCode==FALSE) ) {
      7  // Download active, do something...
      8  }
      9 
      10  instance->out = 0;
      11  p->FB_Init = TRUE;
      12  return;
      13 }
      1 void SimpleCalc__getUserPropVar(SimpleCalc_getUserPropVar_struct *p)
      2 {
      3  p->__getUserPropVar = p->instance->userPropVar * 42.0;
      4 }
      5 void SimpleCalc__setUserPropVar(SimpleCalc_setUserPropVar_struct *p)
      6 {
      7  p->instance->userPropVar = p->setUserPropVar / 42.0;
      8  p->__setUserPropVar = TRUE;
      9 }

  • Finally, register all C/C++ implementations within the runtime to enable call of the function block "<functionblock_name>" and the desired method and properties within a PLC application. The registered names of the C/C++ functions must match the name of IEC function block and the following scheme. The function block name [functionblock_name] must be separated by two underscores from the extension part.
    • [functionblock_name]__[method_name]
    • [functionblock_name]__set[property_name]
    • [functionblock_name]__get[property_name]
    1 WCHAR16 name[MLPI_APPLICATION_MAX_LENGTH_OF_POU_NAME] = L"SimpleCalc__Main";
    2 MLPIPOUFNCPTR function = (MLPIPOUFNCPTR) SimpleCalc__Main;
    3 MLPIRESULT result = mlpiLogicPouExtensionRegister(connection, name, function);
    4 if(MLPI_SUCCEEDED(result)) {
    5  wcscpy16(name, L"SimpleCalc__FB_Init");
    6  function = (MLPIPOUFNCPTR) SimpleCalc__FB_Init;
    7  result = mlpiLogicPouExtensionRegister(connection, name, function);
    8 }
    9 if(MLPI_SUCCEEDED(result)) {
    10  wcscpy16(name, L"SimpleCalc__getUserPropVar");
    11  function = (MLPIPOUFNCPTR) SimpleCalc__getUserPropVar;
    12  result = mlpiLogicPouExtensionRegister(connection, name, function);
    13 }
    14 if(MLPI_SUCCEEDED(result)) {
    15 wcscpy16(name, L"SimpleCalc__setUserPropVar");
    16  function = (MLPIPOUFNCPTR) SimpleCalc__setUserPropVar;
    17  result = mlpiLogicPouExtensionRegister(connection, name, function);
    18 }

  • After the external function is registered, you can download your PLC program and use the function block.
MLPIRESULT mlpiLogicPouExtensionUnregister ( const MLPIHANDLE  connection,
const WCHAR16 name,
const MLPIPOUFNCPTR  function,
const ULONG  signature = 0,
const ULONG  version = 0 
)

This function unregisters a C/C++ implementation of a POU (e.g. function block) at MLPI real-time environment.

Note
This function can only be used within a real-time application on the target and there only within the kernel space! This function is not available in other toolboxes!
Parameters
[in]connectionHandle for multiple connections.
[in]nameName of POU in the IEC 61131 environment.
[in]functionFunction pointer to C/C++ implementation.
[in]signatureSignature of POU interface.
[in]versionVersion of POU library.
Returns
Return value indicating success (>=0) or error (<0).
Example:
1 // Unregister a C/C++ implementation to disable call of function "SimpleCalc" in a PLC application.
2 WCHAR16 name[MLPI_APPLICATION_MAX_LENGTH_OF_POU_NAME] = L"SimpleCalc";
3 MLPIPOUFNCPTR function = (MLPIPOUFNCPTR) SimpleCalc;
4 MLPIRESULT result = mlpiLogicPouExtensionUnregister(connection, name, function);
MLPIRESULT mlpiLogicPouExtensionUnregisterAll ( const MLPIHANDLE  connection)

This function unregisters all C/C++ implementations of POUs (e.g. function blocks) at MLPI real-time environment.

Note
This function can only be used within a real-time application on the target and there only within the kernel space! This function is not available in other toolboxes!
Parameters
[in]connectionHandle for multiple connections.
Returns
Return value indicating success (>=0) or error (<0).
Example:
1 // Unregister all C/C++ implementations to disable all calls in a PLC application.
2 MLPIRESULT result = mlpiLogicPouExtensionUnregisterAll(connection);