External Functions

A POU (PROGRAM, FUNCTION, FUNCTION_BLOCK) can be marked as external, which will cause the compiler to ignore its implementation.

{external}
FUNCTION log : DINT
VAR_IN_OUT
  message : STRING[1024];
END_VAR
VAR_INPUT
  type : (Err,Warn,Info) := Info;
END_VAR
END_FUNCTION

At compilation time, the function log will be defined as an externally available function, and can be called from ST code.

Note: At linking time, a log function with a compatible signature must be available on the system.

Calling C functions

ST code can call into foreign functions natively. To achieve this, the called function must be defined in a C compatible API, e.g. extern "C" blocks.

The interface of the function has to:

  • either be included with the -i flag
  • or be declared in ST using the {external} keyword

When including multiple header files/function interfaces, the -i flag must precede each individual file, e.g. -i file1.st -i file2.st -i file3.st. Alternatively, when including an entire folder with -i '/liblocation/*.st', the path must be put in quotes, otherwise the command-line might parse the arguments in a way that is incompatible (i.e. does not precede each file with -i).

Example

Given a min function defined in C as follows:

int min(int a, int b) {
//...
}

an interface of that function in ST can be defined as:

{external}
FUNCTION min : DINT
VAR_INPUT
  a : DINT;
  b : DINT;
END_VAR
END_FUNCTION

Variadic arguments

Some foreign functions, especially ones defined in C, could be variadic functions.

These functions are usually defined with the last parameter ..., and signify that a function can be called with unlimited parameters.

An example of a variadic function is printf.

Calling a variadic function is supported in ST. To mark an external function as variadic, you can add a parameter of type ... to the VAR_INPUT block.

Variadic function example

Given the printf function defined as:

int printf( const char *restrict format, ... );

the ST interface can be defined as:

{external}
FUNCTION printf : DINT
VAR_INPUT {ref}
  format : STRING;
END_VAR
VAR_INPUT
  args : ...;
END_VAR
END_FUNCTION

Runnable example

With the printf function available on the system, there is no need to declare the C function.

An ST program called ExternalFunctions.st with the following code can be declared:

(*ExternalFunctions.st*)

(**
 * The printf function's interface, marked as external since
 * it is defined directly along other ST functions
 *)
{external}
FUNCTION printf : DINT
VAR_INPUT {ref}
    format : STRING;
END_VAR
VAR_INPUT
    args: ...;
END_VAR
END_FUNCTION


(**
* The main function of the program prints a demo to the standard out
* The function main is implemented at this location and thus not marked
* as {external}
*)
FUNCTION main : DINT
VAR
    tmp : DINT;
END_VAR
  tmp := 1;
  printf('Value %d, %d, %d$N', tmp, tmp * 10, tmp * 100);
  main := tmp;
END_FUNCTION

Compiling the previous code with the following command:

plc ExternalFunctions.st -o ExternalFunctions --linker=clang

will yield an executable called ExternalFunctions.

We use clang to link the generated object file and generate an executable since the embedded linker cannot generate executable files.

The executable can then be started with ./ExternalFunctions.