Using Simulink® Strings

Simulink® strings are explicitly allowed and can be used with the TwinCAT Target for Simulink®.

Restriction

Depending on the MATLAB® release version, code interface packaging setting and the set C/C++ standard, Simulink® Coder™ compiles a Simulink® string into the std::string data type.

If this Simulink® string is used as model input or model output, it should be noted that these entries cannot always be connected to other objects in TwinCAT by mapping. Mapping in TwinCAT assumes a static data type size, which is not the case with std::string.

Using Simulink® Strings 1:

Detailed sample in MATLAB®

The topics for TwinCAT Build 4024 and 4026 are described in detail in this sample:

TwinCAT.ModuleGenerator.Samples.Start('Using Simulink Strings')

Handling with TwinCAT 3.1 Build 4026

The TwinCAT SDK for TwinCAT Builds >=4026 allows the use of a std::string implementation. This means that strings can also be implemented in mapping.

This option has two restrictions:

Use the following settings to successfully build the Simulink® model:

set_param(modelName,'TcProject_CppLanguageStandard','stdcpp20');
set_param(modelName,'TcProject_UseStaticStlString','on');

The size of the underlying character array is set to 256 by default, as configured by the Simulink® parameter DynamicStringBufferSize.

If desired, the size of the underlying character array can be set independently of the Simulink® parameter DynamicStringBufferSize via the project parameter StaticStlStringCapacity:

set_param(modelName,'TcProject_StaticStlStringCapacity','255');

For the TcCOM data areas, the corresponding TwinCAT type for each std::string is a structure type with a data member and a size member. If a string value is set, both the data member and the size member must be set. The size is the length of the character array that will be set to the data value and can be between 0 and the value of StaticStlStringCapacity. Selecting a value greater than StaticStlStringCapacity results in undefined behavior.

The usability of the PLC-FB is similar to the TcCOM module, where std::string is a structure with a size member and a data member. Writing a string value requires both the size member and the data member to be set, while reading a string value may require the user to truncate the string read from the data element to the appropriate size.

Handling with TwinCAT 3.1 Build 4024

So that you can still use the inputs and outputs, it is recommended that the PLC-FB (no mappings necessary) or the TcCOM Wrapper FB are used. For the standard inputs and outputs of the FBs, the Simulink® string entries are not displayed in either case. These are to be set separately via getter and setter methods on the FB.

Using Simulink® Strings 2:

Simulink® bus with Simulink® strings: restricted use

The following situation is currently not supported: a Simulink® string cannot be used in a Simulink® bus that serves as input or output of the model if it is mapped as std::string by Simulink® Coder™.

Sample

Let's take the following Simulink® model with a mixture of string and non-string inputs and outputs.

Using Simulink® Strings 3:

When this model is compiled with MATLAB® R2022a and “C++ Class” code interface packaging, the data type std::string is generated by Simulink® Coder™. In the following figure, it can be seen that the string inputs and outputs are not present in the process image in TwinCAT.
Only the non-string inputs and outputs are present in the process image.

Using Simulink® Strings 4:

To be able to write and read the strings, either the TcCOM Wrapper FB or the PLC FB must be used. Corresponding getter and setter methods are automatically created at the function blocks.

Using Simulink® Strings 5:

Sample code using the PLC-FB:

VAR
   fbStringSample : FB_string_sample;
   
   myStringIn   : T_MaxString;
   myStringOut1 : T_MaxString;
   myStringOut2 : T_MaxString;
   nSize : ULINT;
   nSize2: ULINT;
   fIn   : LREAL;
   fOut  : LREAL;
END_VAR
// put sting input
fbStringSample.put_StringInput(c_str := ADR(myStringIn));

// call function
fbStringSample(fNonStringInput := fIn, fNonStringOut3 => fOut);

// get string outputs 
nSize := SIZEOF(myStringOut1);
fbStringSample.get_StringOut1(c_str := ADR(myStringOut1), size := nSize);  // size in VAR IN OUT!

nSize2 := SIZEOF(myStringOut2);
fbStringSample.get_StringOut2(c_str := ADR(myStringOut2), size := nSize2);