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
logfunction 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
-iflag - or be declared in
STusing 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.