Simulink: Objectoriented connection and Inspector, model guide

Simulink: Objectoriented connection and Inspector, model guide

Inhalt


Topic:.Smlk_Inspc.FB_ObjOConn.

Last changed: 2019-01-03

ObjectOrientation as such means, bundling of data to their operations. For Simulink FBs (Function Blocks) it means, any FBlock, or Module, has its specific data. The assembled data of a FBlock or Module can be presented and forwarded with the simulink standard equipment via a mux (Multiplexer) or via a bus. But how it is with set-operations. Show the right image:


1 Bus vs. Reference

Topic:.Smlk_Inspc.FB_ObjOConn.cmpBusRef.

This chapter compares the classic connection of Moduls via Bus and the connection via a reference


Bild: Two modules bus-connected In this image two modules are connected. One of them should hold the data, the other is a operation which works with that data. That should be the approach of the software structure, that is Object Oriented.

But to rewrite to the data inside the operation a second connection is needed, from the operation, which changes the data, back to the Module which holds the data. That is data flow, the original paradigm of Simulink.


Bild: data module for bus connection

It may be additional confuse-able: The Module which holds the data holds it in unit delays. One per data word. That is data-flow oriented. They are several data. Of course for vectorized data one unit delay is only necessary.

Yet the designer of the model could come to the idea to assemble the unit delay in the 'operation' module, because the new data are calculated there, it is more simple. It is data-flow-oriented. But now the architecture of the software is disturbed, no more separation between data and the operation, no more assemble all data in one module. The data-separation approach may be done for any other reason, not for the details here. It is not possible to enforce it because the data-flow-orientation is petty from this view.


Bild: two modules handle (reference)-connected

Now the two modules are connected via a handle which is a reference to the data. Now it is ObjectOriented.


Bild: data module for reference connection

The module which holds the data has a centralized Function Block of type lib_Inspc/DataStructMng_Inspc which is contained in the lib_Inspc. It can hold up to 6 data elements which any number of array size, and it can cacaded with some more such FBlock to one data struct.


Bild: operation module for reference connection

The operation should rewrite the data. How to do it without a back-connection (data-flow thinking). Of course, it is possible with a set-Operation. That are the two right FBs which accesses the data. The access FBs of type get/set_DataStruct_Inspc know the data via the handle input.

Code generation support:

For code generation (Simulink embedded coder) both FBs produces a typename.h Headerfile in its runtime which presents the connected and parametrized values in a struct with access operations (getter, setter). The tlc-File to control the target language compiler for the Simulink coder takes special run-time-parameter, which are produces too on runtime of the FBs. So the generated code is optimized for access to the bundled data depending of the model-specific properties of the instances in the model.

Access to the data via inspector:

Last not least there is a FBlock Service_Inspc and one or more tools to access the data. The Service can also run in the target system, the data are bundled ObjectOriented there too. It is data viewing, which is an important medium to explore and evaluate the software in runtime.


2 Special data struct FBlocks in C

Topic:.Smlk_Inspc.FB_ObjOConn.structC.

It is possible to program the data for the graphic modules in typedef struct definitions with getter and setter operations which are compiled as special Sfunctions, see Topic:.Smlk_de.C_ObjO.genSfH..

For special issues a special solution in C as Sfunction may be proper.

The disadvantage for a common usage is: Small changes in the model may need adapting in the C-sources and newly translating the Sfunction (mex-Compiler). It is a break in the concept of the currently engineering.

Therefore a set of Sfunctions ready to use are provided in the lib/Inspc.slx Library. This library is favorized because the data are able to inspect too. The service_Inspc is not necessary for this FBlocks. See next chapter.


3 Overview ...DataStruct_Inspc FBlocks

Topic:.Smlk_Inspc.FB_ObjOConn.dStructFB.


Bild: DataStruct_Inspc in lib_Inspc

The right image shows the FBlock in the library:

The following 3 Types of DataStruct definition FBlocks should be placed in one module to build the data struct.

The following Types of DataStruct access FBlocks can be places especially in other modules for data exchange or in the same module to build a data storage (as unit delay):


4 Application notes of the DataStruct_Inspc FBlock family

Topic:.Smlk_Inspc.FB_ObjOConn.appl.

Last changed: 2018-11-14

The FBlocks to build and access Data are arranged in the Library lib_Inspc.skx because a substantial feature is the assignability to data with the Inspector Service.


4.1 Example with two cascaded ''DataStruct_Inspc'' FBlocks and one ''get_DataStruct_Inspc'' FBlock

Topic:.Smlk_Inspc.FB_ObjOConn.appl.exmpl_A.


Bild: Application example

The FBlock with 'M' named thiz is the DataStructMng_Inspc from the lib_Inspc.slx. The first 4 Inputs are connected from several signals inside this module. The types of the signals can be different. In this image the types are visible (Display - Signals and Ports - Port Data Types) is switched on to demonstrate it.

The output of this FBlock is a handle as uint32-type. It is named thiz because it presents this data for the module, adquate to usage of this in C++. It is named thiz to prevent name clashes for C++ target code generation. The handle is converted to a pointer to the data in the using Sfunctions, for target code the handle presents the 32-bit-memory address of the data immediately and optimized.

The second FBlock with 'i' is a cascade with a Init_DataStruct_Inspc SFB from the lib_Inspc. It is especially used for the initial wiring of Blocks and modules: In ObjectOrientation associations and aggregations are need. That are references to other Objects. Aggregations are connected in the startup phase, and after them they are fix. Associations can be switched on runtime. That is the wording of UML. The Tinit step (or sample-) time is the one where initial wiring for aggregations are done. It is support by this FBlock: The special feature is: The types of the input references are checked. It is a typecheck on startup time in this module, independent of this feature the types are checked in the using Blocks again. The typecheck here helps to detect model errors local in the module.

The FBlock f_Y12 is an instance of get_DataStruct_Inspc. It uses the thiz output via Goto-From-data connection. This FBlock is used to access a value from the DataStructMng_Inspc thiz. Its output is named f_Y12_z because it is the value from the last step time. It acts as unit delay. The DataStructMng_Inspc writes the data in the mdlUpdate routine as last action of the step time, so the access is done to the value from the previous step time. With them a numeric loop is prevented, and the delayed f_Y12_z can be used to calculate the new value of this signal with the shown += operation. That is an integrator function.

The get_DataStruct_Inspc accesses the data from the last step time in any case. The combination of this with the DataStructMng_Inspc and a DataStruct_Inspc for cascade acts as unit delay. That is important to exactly implement the integration of differential equations and to prevent data consistent conflicts.


4.2 Example of a set and get in another module

Topic:.Smlk_Inspc.FB_ObjOConn.appl.exmpl_B.


Bild: Application access example

The right image shows the access to the data of the struct of the last chapter. It is assigned in another module via a port connection. The Fblock after the inport checks the type of the handle on runtime of Simulink and determines the type of access for the generated code via tlc-files. It is a handle-type check & cast FBlock. The 3 connected FBlocks reads and writes data. The tune_fY12 writes the named data element with the result of the mulitplication. The par_PID gets the value on init time for aggregation, in this case of the parameter Fblock to the PID controller Fblock. The yellow values shows handles which represents pointer values. The f_Y12 outputs the value of the Variable ..f_Y12.


4.3 Example of polymorphism

Topic:.Smlk_Inspc.FB_ObjOConn.appl.emxpl_supersub.

The polymorphism is an important capability of ObjectOrientation: An instance can be associated via an basic type, the usage should not know the exact implementation type. This helps to deal with several versions of implementation, maybe because a development progress, maybe because different implementation variants in a more universal basic frame. https://en.wikipedia.org/wiki/Polymorphism_(computer_science)

The below image shows an enhancement from a DataStructMng_Inspc chain of Type Controller_ObjMod to a Type Controller_B_ObjMod. The story to do so is:


Bild: Super and Sub Type with DataStructMng

The solution, showing right, shows the first interface unchanged, with the right chain of DataStruct FBlocks. The output type is unchanged, it is Controller_ObjMod. The generated header files are unchanged (important!).

The blue left FBlock is the new one. It is a DataStructMng_Inspc which thiz-Output is connected to the 7. input of the otherwise unchanged DataStructMng_Inspc right. Because of this connection the left blue DataStructMng_Inspc receives the Type and the memory amount from the right one, via back writing via the given reference. The left blue DataStructMng_Inspc creates the memory for both and assigns the data of the right one as superType. The output pointer refers a data struct with the more comprehensive data of Type Controller_B_ObjMod but the access type is Controller_ObjMod nevertheless. This is the known subtype/superType arrangement from inheritance in ObjectOrientation.

The used wording is:

This terms should be applicated to GraphicalProgramming with Simulink now.


4.4 Example build a comprehensive module or a component

Topic:.Smlk_Inspc.FB_ObjOConn.appl.parent.

A modulare design is subdivided into components, higher-level and sub-modules. This is particularly noticeable in graphic programming.

The following wording is used, in coordination to the wording of ObjectOriented inheritance and abstraction with the subType and superType:

The usage of wording module is related to instances in this focus. 'Module' is also used for the structure of sources in programming, but that is another direction of thought.


Bild: parent dataStruct

With this linguistic basics let's have a look to build parent modules. The image above can be designated as a component, or a parent module of some sub modules. It does contain only less processing of signals, more interconnections of its sub modules. The DataStruct of this component or parent module is build in the same way as a all DataStruct in the above examples. Only the input signals are typical outputs of the sub modules. Because the DataStructMng_Inspc does not gather signals in the Tinit initial step time, some signals of the fast step time are connected. The other TinitDataStruct_Inspc (here only one, typically maybe more) gathers the Outputs from the modules which are aggregations to the sub modules from view of this module, wired in the Tinit step time.

The type of data of the myDevice is Device_ObjMod, appoint as parameter in the DataStructMng_Inspc FBlock.


4.5 Example Access to sub modules with Polymorphism

Topic:.Smlk_Inspc.FB_ObjOConn.appl.accessSub.


Bild: Access in another component

This right image shows the access to the polymorph given data, but the polymorphismus is not really considered. This is the module which uses the unchanged, see Chapter: 4.3 Example of polymorphism. The Input is connected to myDevice from the chapter above, its type is Device_ObjMod. The type have to be determined here using the checkCast_DataStruct_Inspc FBlock. It checkes the correct type in Simulink startup-runtime and forces an error message on faulty connection. That is important because the input is somehow wired, errors are possible.

The other importance is: This FBlock offers the type information for code generation with the Simulink or Embedded Coder. The following get_Access_DataStruct_Inspc or set_.. FBlocks gets the information about the type from the connected inputs (Hint: via srcBlock = LibBlockSrcSignalBlock(0, 0) and CompiledModel.System[srcBlock[0]].Block[srcBlock[1]] in the tlc-File).

In this module the reference and current value should be subtract from the controller sub module. Therefore the shown blue controller Fblock accesses this sub module reference from Device_ObjMod. The output type in Simulink Runtime is determined by the Reflection, it is either Controller_ObjMod or the subType Controller_B_ObjMod, see Chapter: 4.3 Example of polymorphism. The inheritance to the subType is transparent here. The superType Controller_ObjMod is used. Because the following FBlocks need this type information for the generated code, the type is parametrized here. In Simulink runtime the parametrized type is tested, it is true independent of the polymorphism. Because it is tested, it can be unquestionable used for the code generation.

The yellow boxed area can be a Fblock in a Simulink library. The Controller_ObjMod can be established as one library. Then it can contains some such yellow Fblocks. This Fblock can be considered as operation of the class Controller_ObjMod. It is a static (not dynamic linked) operation. The calling of a class-operation in C++ is exactly the same as the usage of a lib-module in Simulink.

To work with dynamic linked operations (virtual), the operation cannot be included or called immediately, in C++ it is linked on runtime via the so named virtual table. The proper counterpart in Simulink is a Triggered Subsystem, see ../../smlk/html/TriggeredSubsystem.html. The triggered subsystem is arranged inside the maybe inherited main module for the controller, the inherited module can contain another incarnation for the triggered subsystem. The trigger is forced in the using module. The trigger does not know what is executed, that is the late linkuage of dynamic calls.


5 Parameter of FBlock ''DataStructMng_Inspc''

Topic:.Smlk_Inspc.FB_ObjOConn.DataStructMngPar.


Bild: Parameter of FBs

The DataStructMng_Inspc has the following parameter:


5.1 Parameter of FBlock ''DataStruct_Inspc'' and ''InitDataStruct_Inspc

Topic:.Smlk_Inspc.FB_ObjOConn.DataStructMngPar.DataStructPar.


Bild: Parameter of FBs

Both FBlocks have a similar Parameter Dialog. The InitDataStruct_Inspc has additional features, therefore it is shown here.

The FBlock InitDataStruct_Inspc transfers numeric initial values or references in the Tinit step time. The DataStruct_Inspc does the same as dataStructMng_Inspc with the data. Both build a a cascade with the DataStructMng_Inspc as common last member. The last one holds the data, writes the header etc.


6 Parameter of FBlock ''get_DataStruct_Inspc''

Topic:.Smlk_Inspc.FB_ObjOConn.get_DataStructPar.


Bild: Parameter of FBs

The get_DataStruct_Inspc can get and output the stored data in any step/sample time.


7 The ''set_DataStruct_Inspc'' FBlock and its Parameter

Topic:.Smlk_Inspc.FB_ObjOConn.set_DataStructPar.

Last changed: 2018-11-14

Like shown in Topic:.Smlk_Inspc.FB_ObjOConn.appl.DataStructMngPar. the DataStructMng_Inspc and DataStruct_Inspc can define a variable but set only with an initial value. The name parameter should be written in {...}. The value can be set with a set_dataStruct_Mng. This possibility should be discussed under the Object Oriented aspect:


Bild: Application of set_DataStruct_Inspc

The image right shows a set_DataStruct_Inspc FBlock for the signals tunefY12. This signal is build in the controller and set set into the data of the module parOptimizer. From view of the parOptimizer it is an input for a optimizing process. The parOptimizer determines the meaning of this input. The controller should deliver the proper signal.


Bild: two variantes of get...

This image shows an experience model detail from the parOptimizer. The first variant is: Existing output values of the controller are used and combined. If the controller has the proper public data values, it is ok. In this case the parOptimizer should know which values are proper from the controler to work, it should have knowledge about the functionality of the controller. The controller does not need any knowledge about the parOptimizer.

The alternative is: The own value tune_fY12 is used which is set in the controller. In this case the controller should determine the algorithm to tune the factor f_Y12. The module parOptimizer is only the execution instance. The controller should know which values are proper for the input to the parOptimizer. The controler should know something about the parOptimizer, but only on its given interface. The parOptimizer should nothing know about the controller. It gets the input and works with them, no more.

Which knowledge relation is better for the design, that is a decision of the cooperation between the modules, a design or architecture decision, not a model decision. For the modelling, both decisions are equate.

The design or architecture desicision is shaped by considerations about changing of some details of the moduls, about responsibilities or such considerations.


Bild: Parameter of FBlock set_DataStruct_Inspc

The parameter are similar the get_DataStruct_Inspc.


8 Tree of DataStructMng_Inspc for nested modules

Topic:.Smlk_Inspc.FB_ObjOConn.tree.

Last changed: 2018-11-02

If you have submodules in modules, any submodule may/should have its DataStructMng_Inspc FBlock which presents the module data.

In the superior module the handle of the submodules are connected to the DataStructMng_Inspc of this module. The next image show that:


Bild: treed module references

You see a snippet of a modulare structure. Some modules have its thiz output. They are connected to a 'goto' FBlock, a corresponding 'from' FBlock is the source for an input of DataStructMng_Inspc. Usage goto/from is a proper design style to prevent too much lines for regular connections.

The inputs which comes from the submodules, repspectively all inputs which are handles (from in C written Sfunctions too are marked with * before the name. It is semantically known from the pointer access in C-language. Here it means, the input is not a simple uint32, it should be recognized as handle.

You can access from outside to a deeper level in a module/submodule with the Out_DataStruct_Inspc FBlock with writing a path separated by a dot:


Bild: Access path to a submodule

From view of the model it is similar a 'from' from a global 'goto': It is a stand alone FBlock with a textual given source. But global goto/from can be seen as nuisance for modularization. The source of this block is systematically.

From view of ObjectOriented access it is an access to an inner class (concatenated associations) whereby the inner class is gotten via its direct reference, not with a get-method. It is quite usual in ObjectOrientation. It saves access routines respecitively ports and lines in the model.


9 Connection and Access via Inspector Service

Topic:.Smlk_Inspc.FB_ObjOConn.inspc.

Last changed: 2018-11-02

The Inspector Service cann access all data which are based on ObjectJc, and all data which's reflection are known beside its struct definition. The DataStructMng_Inspc is based on ObjectJc. The reflection of DataStructMng_Inspc are created dynamically depending of the model and connected signals.

You only need connect the most superior DataStructMng_Inspc to the Inspector Service. All submodules are successfully connected if you build a tree of DataStructMng_Inspc proper to the tree of module structure.

The image shows the connection:


Bild: Connection to Inspc Service

A add_DataNode_Inspc FBlock is used. That FBlock contains an argument for the name of the DataStructMng_Inspc data struct for the access. For the inspector service concept see Chapter: 9 Connection and Access via Inspector Service.


Bild: Fiels of fist level In this constellation you can open the Inspector-Tool and view fields of the first level. You see:

More aggregations (modules) are existing if more as one are registered via add_DataNode_Inspc, for example parts or the whole simulation environment.


Bild: Fiels of second level

If you click into myDevice you see the modules and signals of the device of the first level according to the DataStructMng_Inspc FBlock and the deeper levels:


Bild: Fiels of second level

If you have the access password:


Bild: password diaglog

The passwords are hard coded in the standard implementation of the Inspector GUI and the emc access sources:

If you use the Inspector and a target system for a customer, you should implement the necessary special password protection.


Bild: developer access You see more fields, especially 'super' via super.thiz1 you can access internas of the FBlock to view its implementation, as developer access:


Bild: developer access

This shows data, which are gathered from the simulink model on startup of the simulation: TstepMin = minimum of step times of all inputs, here 0.0001 s, index of the ports etc.


10 Code generation contribution for Simulink Embedded Coder

Topic:.Smlk_Inspc.FB_ObjOConn..

There are two contributions:

1) The FBlock DataStructMng_Inspc-instances produce C-Headerfiles and C-files depending on its parameter and connected inputs in the Simulink run time (on test of the model). That files are used in the target code.

2) The special adapted tlc-files for this FBlocks organize the call of that code.


10.1 Generated code of ,,DataStructMng_Inspc,,-instances

Topic:.Smlk_Inspc.FB_ObjOConn..DataStructSrc.

The DataStructMng_Inspc has a parameter fileDir - genSource. This parameter should be set with a variable. If the model runs in some simulation situations, that variable should be set with an empty string ''. Then no code generation is done. For the last simulation run before code generation that variable should be set with the file path to the directory where generated files are stored. Then the generation is done. See as example the _init.m mat script:

%dstPathGenDataStruct = '';   %%left empty if no code generation is used yet.
dstPathGenDataStruct = 'test/+ObjOModule_ExmplCtrl/Cprj/genSrcInspc';


Bild: Parameter DataStructMng_Inspc

The last directory of this path have to be genSrcInspc like shown here. This directory is used in the generated source in the include statement, see below.

In the headerfile a struct will be created with the type and parametrized name constellation of the instance in the model- The file looks like (example .../genSrcInspc/)

struct PID_Ctrl_t;
struct MeasPrep_ProgrSimpleExmplA_t;
typedef struct Controller_ObjMod_t {
  union { ObjectJc object; } base;
  float W[2];
  int xMeas;
  float yctrl[2];
  .....
  struct PID_Ctrl_t * pid2;
  struct MeasPrep_ProgrSimpleExmplA_t * xMeasRef;
} Controller_ObjMod_s;

The struct is based on ObjectJc which is necessary for ObjectOrientation for type check and for reflection access (Inspector). In a spare target software constellation this base structure can be reduced to 1 int variable for an ident number and the index of the type. This is enough for the Inspector-Target-Proxy concept (see InspcTargetProxy) or for low level debug.

The data names come from the parameter, see right image. The types come from the connected inputs from the model. The access rights are for the Inpector access. Not parametrized names or not used inputs do not contribute to elements in the struct.


Bild: Parameter InitDataStruct_Inspc

The two last elements in this struct comes from the chained FBlock. Because it is a Init... FBlock the struct type is given and used as forward declaration. All chained FBlocks builds one struct. The FBlock Type DataStructMng_Inspc is the manager of the chained blocks.

.
.
.
.
.
.
.
.
.
.
.

The headerfile contains the prototype for the constructor and the write... routines for the DataStruct definition FBlocks:

void ctor_Controller_ObjOModules(Controller_ObjOModules_s* thiz);

/**Write data to DataStruct.
 * Note: The Simulink coder cannot decide whether it is a scalar, vector or poitner
 * Therefore all arguments are unique given as address (pointer)
 */
void init__Controller_ObjMod(Controller_ObjMod_s* thiz, float* W, uint32* xMeas, float* yctrl, int32* testtt, float* Y);
void step__Controller_ObjMod(Controller_ObjMod_s* thiz, float* W, uint32* xMeas, float* yctrl, int32* testtt, float* Y);
.....
void init_i3_Controller_ObjMod(Controller_ObjMod_s* thiz, uint32* pid2, uint32* xMeasRef);

Any FBlock of the chain have an init_... and a step_... routine. They are called in the Tinit step time for initialization and in the appropriate step time of the Fblock, which can be different for each chained block. It is organized in the tlc files.

The getter routines for all data elements are generated as inline functions to get a fast access:

inline void get_W_Controller_ObjMod(Controller_ObjMod_s* thiz, float* W) {
  memcpy(W, thiz->W, sizeof(thiz->W));//float
}
inline void get_xMeas_Controller_ObjMod(Controller_ObjMod_s* thiz, int* xMeas) {
  *xMeas = thiz->xMeas;
}

The calling environment in the modell does not know the type of the connection, only the name. Therefore all accesses are done with a address reference, which is the reference of the destination variable. But the type of the data are well defined in the generated code from the simulink coder. The here generated operations knows the type and vector situation from the simulink running environment. Both matches, if the code generation for the model with the Simulink Coder and the generation of this sources is done with the same model situation. Elsewhere the discrepancy is detected by an compilation error because pointer type mismatch. If a vector access used in the model, a memcpy is done in the generated code. The size of the vector is defined by the sizeof(...) of the destination variable from generated code proper.

From another example header ParameterOptimizer_ObjMod.h:

typedef struct {
  ....
  float tune_fY12;

  struct Par_PID_Ctrl_t * par_PID;
} ParameterOptimizer_ObjMod_s;


inline void get_par_PID_ParameterOptimizer_ObjMod(ParameterOptimizer_ObjMod_s* thiz, uint32* par_PID) {
  *par_PID = HANDLE_Handle2Ptr(thiz->par_PID);
}


Bild: Out_DataStruct_Inspc_Tinit

The get_par_...(...) is the access with the right shown FBlock: The type in the model and in the generated source is uint32, a handle. The meaning of the data is a reference (address, pointer value). In the struct the exact typed reference is stored how it is given in the appropriate DataStructInspc definition block where the type of the handle/reference is parametrized. The access converts the address value in the struct to the handle value. For a 32-bit target system it is an empty macro, only a type casting.

.
.
.


Bild: InitDataStruct_par_PID

This is the appropriate InitDataStruct_Inspc FBlock, which's parameter defines the type. The type is tested in the Simulink run mode by reflection check, used for code generation and used in the target software. The variable of the code generated code are of type uint32. The HANDLE_Handle2Ptr is a simple macro which contains only a type cast if the target system has 32-bit-addresses. The address is stored immediately in the uint32 variable of the model. On low-level-debugging (single step) in the target code the correct type can be evaluated for showing the content in the debugger from the struct variable, that is explicit helpfull. The type is used for Inspector access on the target too. The reflection generation is done from this generated header file.


Bild: set_DataStruct_Example

inline void set_tune_fY12_ParameterOptimizer_ObjMod
  (ParameterOptimizer_ObjMod_s* thiz, float* tune_fY12) {
  thiz->tune_fY12 = *tune_fY12;
}

The generated code for the right FBlock is shown above. It is adequate the get routine. direction is reverse. For vector assignments a memcpy is used too.

.
.
.
.


Bild: DataStruct_forSet_ParamDlg

The special provocation for the set FBlocks is: The associated DataStruct_Inspc FBlock must not set this value in any step time, only in the Tinit time as initial value. This is done via the 100 value of access rights in the parameter dialog. The 107 means additionally read only access.


10.2 tlc-file adaption to organize the call if the getter/setter

Topic:.Smlk_Inspc.FB_ObjOConn...

Some manually adapted tlc files are contained in .../lib/+mkSfn/tlc_src/*.tlc and copied from there with the mex compilation to the adequate mex/tlc_c directory. The automatic generated tlc files (see Topic:.Smlk_de.C_ObjO.genSfH.) are stored as .../lib/+genSfn/Inspc/*.tlc

The tlc file is hand-written. The get_Access_DataStruct_Inspc_SfH.tlc contains the following code (shorten):

%function OutputsForTID(block, system, tid) Output
  .....
%if tid == tidStep
  %assign srcBlock = LibBlockSrcSignalBlock(0, 0)
  %assign sys1 = srcBlock[0]
  %assign blk1 = srcBlock[1]
  %assign block1 = CompiledModel.System[sys1].Block[blk1]
  %with block1
    %assign typeData = SFcnParamSettings.typeData_param
  %endwith
  {
    //The input is the reference to the created struct from DataStructMng_Inspc. The connected ...
    //The dwork is not used: %<LibBlockDWork(thiz_h, "", "", "0")>
   %<typeData>_s* pData = PTR_Handle2Ptr(%<LibBlockInputSignal(0, "", "", 0)>, %<typeData>_s);
   *(%<LibBlockOutputSignalAddr(0, "", "", 0)>) = get_%<SFcnParamSettings.name_param>_%<typeData>(pData);
  }
%endif
%endfunction

The generated codes come from the parameter settings, not from the C-functions of the Sfunction:

Adequate it is for the set_DatatStructMng_Inspc_SfH:

%function InitializeConditions (block, system) Output
 //Initialize the handle2Ptr-Mechanism on 64-bit-Systems if not done already:
 INIT_Handle2Ptr();
 { //jzTc: malloc for %<Type> %<ParamSettings.FunctionName>: %<Name>
   %assign hthizAddr = LibBlockDWorkAddr(thiz_h, "", "", "0")
   //create data for SFBlock= %<LibGetFormattedBlockPath(block)>, Type= step_DataStructMng_Inspc_SfH
   %<SFcnParamSettings.typeData_param>_s* thiz = (%<SFcnParamSettings.typeData_param>_s*) malloc(sizeof(%<SFcnParamSettings.typeData_param>_s));
   memset(thiz, 0, sizeof(Data_TestDataStruct_genc_s));
   init_ObjectJc((ObjectJc*)thiz, sizeof(Data_TestDataStruct_genc_s), ident_newAllocated_ObjectJc);  //set the length in ObjectJc for test.
   //NOTE: for 64 bit accelerator mode: register the pointer. Set hthiz. For 32-bit target it is a simple macro.
   registerPtr_Handle2Ptr(thiz, "%<SFcnParamSettings.typeData_param>", %<LibBlockDWorkAddr(thiz_h, "", "", "0")>);
 }
%endfunction

The DWork pointer is used in the originally Sfunction Wrapper to store the thiz-pointer to the struct DataStructMng_Inspc_t* which is more complex. For the generated code only the generated struct ...Type... with the Type from the paramter settings are present. The Type is stored as typeData_param. The data are created dynamically in the target system too, the handle is stored in the DWork.

%function UpdateForTID(block, system, tid) Output
 %assign tidInit = LibGetGlobalTIDFromLocalSFcnTID("OutputPortIdx0")    %%The TID for step_, the first step input port.
 %assign tidStep = LibGetGlobalTIDFromLocalSFcnTID("InputPortIdx0")    %%The TID for step_, the first step input port.
 %if tid == tidInit
 %%nothing Update in init
 %elseif tid == tidStep
 { //jzTc: update for %<Type> %<ParamSettings.FunctionName>: %<Name> (%<LibGetFormattedBlockPath(block)>), TID = %<tidInit>
   %assign hthiz = LibBlockDWork(thiz_h, "", "", "0")
   %<SFcnParamSettings.typeData_param>_s* thiz = PTR_Handle2Ptr(%<hthiz>, %<SFcnParamSettings.typeData_param>_s);
   %%
   %%It checks the name parameter and the connection on an input. Not connected inputs: the possible element remain unchanged, it is 0.
   %%
   %if (SFcnParamSettings.n1_param !="" && LibBlockInputSignalConnected(0))  %%only on given name:
     thiz->%<SFcnParamSettings.n1_param> = %<LibBlockInputSignal(0, "", "", 0)>;
   %endif
   %if (SFcnParamSettings.n2_param !="" && LibBlockInputSignalConnected(1))  %%only on given name:
     thiz->%<SFcnParamSettings.n2_param> = %<LibBlockInputSignal(1, "", "", 0)>;
   %endif
   %if (SFcnParamSettings.n3_param !="" && LibBlockInputSignalConnected(2))  %%only on given name:
     thiz->%<SFcnParamSettings.n3_param> = %<LibBlockInputSignal(2, "", "", 0)>;
   %endif
   %if (SFcnParamSettings.n4_param !="" && LibBlockInputSignalConnected(3))  %%only on given name:
     thiz->%<SFcnParamSettings.n4_param> = %<LibBlockInputSignal(3, "", "", 0)>;
   %endif
   %if (SFcnParamSettings.n5_param !="" && LibBlockInputSignalConnected(4))  %%only on given name:
     thiz->%<SFcnParamSettings.n5_param> = %<LibBlockInputSignal(4, "", "", 0)>;
   %endif
   %if (SFcnParamSettings.n6_param !="" && LibBlockInputSignalConnected(5))  %%only on given name:
     thiz->%<SFcnParamSettings.n6_param> = %<LibBlockInputSignal(5, "", "", 0)>;
   %endif
 }
 %endif
%endfunction %% Update