Function Block group DataStruct_Inspc for Connection of Modules date=2020-01-12

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 images of the following chapter:

History: This FBlocks for building data structs are defined newly about march-2019, used in some applications, but are documented yet only now in 2020-january.

1. Bus vs. Reference-Handle

@ident=cmpBusRef @date=2020-01-12

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

ModuleCon Op2Mdl

The first image shows two modules. Originally it could have been one module, but a part of the too much functionality may be removed from stock. Now there is a data flow between the orginally associated functionality. A simple begin of confusion.

.

.

ModuleCon Bus Some more data are necessary from ,,M_B,, to ,,M_A,,. The last one, the original or first, should be the 'module'- FBlock which holds the data in an Object Oriented approach. Some data are transferred from A to B.

But to rewrite to the data inside the operation ,,M_B,, some back connections are 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.

ModuleCon Bus holdsData

If the data should be consequently hold in the ,,M_A,, it needs a storage. In a classic data-flow-oriented design the storage is inside any FBlocks, last not least usually it is a kind of the here shown ''unit delay''.

Because of the data should be explicitely designed, unit delays are used explicitely in the 'module'-FBlock ,,M_A,,. Because of its content should be get and set by several operations and the 'object oriented' data flow should be simple visible, left and right of them is a bus which’s definition defines the data of this ObjectOriented approach. 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 seems to be more simple. It is data-flow-oriented. But hence the architecture of the Object-Oriented software is disturbed, no more separation between data and the operation, no more assemble all data in one module.

ModuleCon Hdl

The bus definition may be seen as elaborate and non-flexible. There is a more simple approach using special FBlocks as S-Function (in C) which holds the data internally instead using graphical unit delays. The FBlocks are textual parametrized in the Simulink model to define kind and number of data. No (C/++) programming is necessary. As additonal feature the internal values can be set from a file content [[TODO timesignal values], and the content is accesible via Socket connection if the Inspector-Service FBlock is connected with them.

Hence the two modules are connected via a handle which is a reference to the data. Now it is really ObjectOriented. The handle is an identifier (numerical) for the module data on memory. It is the memory address for a 32-bit-System after code generation. For simulink usage the memory address may be 64 bit, and a problem of memory isolation exists between several ''mex'' moduls of the S-function. Hence the handle is used here, it is a 32 bit value, but in a lower range, it is an index to a memory address table.

One can ask, what about the dataflow principle: Well, there is a data flow, the module FBlock gives its information about the memory to its associated operation FBlock.

If the operation is only reading, the data flow adequate to the ''functional programming approach'' is considered. If the operation is writing, it '''is''' a writing operation for this module outside of the module FBlock in respect to Object Oriented Programming with private access of the own writing operation to the module. The only one extraordinariness for classic data flow /FBlock programming is: It is outside the module. The advantage: Improved design ability.

What about faulty connections, memory mismatch: That is proper. The receiving FBlock checks the content of the referenced memory via Reflection, the type should be match. Only suitable FBlocks can be connected together. A non conform connection is reported on start of the simulation as error.

ModuleCon Hdl holdsData

The module which holds the data contains a Function Block of type ''lib_Inspc/DataStructMng_Inspc'' from the ,,lib_Inspc,,-Library. It has inputs for all data, maybe used as initial inputs only (the 3. and 4. input here) or in Runtime (the first 2 inputs here). The definition of input number and kind is given here with the simple textual parametrizing:

s1,s2;
=a, =b;

It defines the name of the 4 Inputs. The type depends from the wired signals (inherit) or can be defined in the parametrize area, also for array types. The ,,=,, means, the input is the initial value only.

Here shown, the access to data is done with the small FBlocks designated as ,,a,, and ,,b,,. They are of type ''lib_Inspc/get_DataStruct_Inspc'' which the proper Parametrizing to access one value of the data.

ModuleCon Hdl changesData

The image right shows access and set of data. How to do rewrite of data without a back-connection (data-flow thinking). Of course, it is possible with a set-Operation. That is done with the two right FBs ,,a,, and ,,b,,. It are of type ''lib_Inspc/get_DataStruct_Inspc''. The second input is the handle which refers the memory for the data. The first input is determined by the parametrizing for the selected data field in the data struct. The step time (sample time) can be any one. The data consistence is in the hands of the developer, some helper (locking mechanism, double buffering) is possible. In a classic dataflow design rate transitions cannot resolve any data consistence problem. But that is a more complex topic.

'''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

@ident=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

@ident=dStructFB @date=2020-01-12

lib Inspc DataStruct

The right image shows the FBlock in the library:

The both left Types '''DataStruct definition FBlocks''' should be placed in a module to build the data struct.

  • ,,DataStructMng_Inspc,, is the managing FBlock for one data struct. The number of inputs depends on parametrizing. An example is contained in the Library ,,lib_Incpc,,.

  • ,,DataStruct_Inspc,, extends the inputs. It builds a chain with any number of it and the only on ,,DataStructMng_Inspc,,. This chain can be used to arrange some data inputs in several positions of the 'module'-FBlocks or maybe in local subsystems of this FBlock model.

The right shown Types of '''DataStruct access FBlocks''' can be places especially in other modules for data exchange or in the same module. The comment on the library and the given templates for parametrizing may shown its functionality.

It includes the transfering of an ''Function call'' which is used for ''Function call subsystems'' or for events for ''Statechart''-FBlocks. This functionality includes a ''event queue'' for the function calls, able to use for a standard event-queue behaviour for state charts in Simulink adequate to the approaches for example in UML (Harel-Statemachines).

The ,,checkCast…​,, FBlock is necessary for module-passing connections especially for code generation: The simulink engine can check the content of a handle, usage of this FBlock is only additional, but the code generation should have informations about the data type which is given here.

4. Inspector data access

@ident=inspc @date=2020-01-12

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.

The access via Inspector is a core feature. It was originally developed for data access in embedded target systems (programmed in C or C++) and adapted to Simulink especially for C-S-functions. Because of data of the object oriented approach should be able to view and set with diagnose tools, the Inspector approach in integrated here, but it is not necessary for work only with the data structures. Especially the ''service_Inspc'' FBlock is only for simulink and should be placed outside of code generation. For the inspector service in the target system special C-sources are necessary which are adapted to the special conditions of the target.

lib Inspc Service Inspc

The right image shows the clipping from the ''lib_Inspc'' with this FBlocks. A part of the image above (chapter above) is visible. The first output of the ''DataStructMng_Inspc'' is an adequate node input for the ''add_DataBide_Inspc''. It it is added as data node is is arranged in the data tree of the inspector viewing tool. The same can be done with any user-defined S-function which has reflection deterministic (it is necessary to define the data).

The only one time necessary ''service_Inspc'' processes the data traffic with the viewing tool of the inspector, via socket connection. The right ''GetValue_Inspc'' FBlock enables access to any data which is added as node, from the simulink model level.

The time signal Function blocks, containing in this ''lib_Inspc'' too, can be added as node too (not shown here, see [[todo].

5. Application notes of the DataStruct_Inspc FBlock family

@ident=appl @date=2020-01-12

The following application notes are derived from a example model ,,ObjOModule_ExmplCtrl,,, see referenced zip file. The model contains two PID controller, one with simulink standard FBlocks (from ''Continous''-Standard-Library), the other one is created as S-Function. The model contains a parameter optimization with measurement of the area of the controller deviation.

5.1. Example with ''DataStruct_Inspc'' FBlock usage

@ident=exmpl_A

DataStructMng appl A

The FBlock with 'M' named ,,thiz,, is the '''DataStructMng_Inspc''' from the ,,lib_Inspc.slx,,. The Inputs are connected from several signals inside this module. The types and sample times 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 in the ,,Tinit,,-Sampletime. 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 inputs 5 and 6 are handle from other ''DataStructMng_Inspc''-Fblocks or from C-programmed S-Functions which uses Reflection. In this example the ,,pid2,, is the thiz-Output from the ''PID_Ctrl'' FBlock which is such an S-Function. The value is a handle which is transferred in the ,,Tinit,,-time (here designated as ,,D2,,). 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 Number -22 for this both Inputs is a designation for access rights for the Inspector tool. The access and changing of values can be secured via a password.

DataStructMng appl B

The right image shows an example from another module, it is the ''parameter optimizer'' module which has its own data. In this case the data ,,f_Y12,, is associated via a small ''get_DataStruct_Inspc'' connected via the ,,thiz,, ''From - Goto'' pair instead directly usage of this signal. It is a delay of one sample step because the calculation order is: writing to the thiz-FBlock is done at least (it is a data destination in data-flow-order), but reading from the f_Y12-FBlock is done first, it reads the value from the last sample time. This is a principle. Access to the data accesses the data from the last sample time inside the same module.

5.2. Example of a set and get in another module

@ident=exmpl_B

Access DataStruct sample

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 2 connected FBlocks read data. The ,,par_PID,, gets the value on init time for aggregation, for this example from 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,,. The order of access depends on the data flow between the modules. If the accessing module is calculated because of other data flows after the writing module, it reads the last written value which is the current value of the sampling time. The calculation order of FBlock which are submodules is considerate as such. The access to DataStruct subordinates to that.

set DataStruct Example

The ''DataStructMng_Inspc'' and ''DataStruct_Inspc'' can define a variable but set only with an initial value. This possibility should be discussed under the Object Oriented aspect:'''

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.

5.3. Example of polymorphism

@ident=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:

  • Firstly the right FBlock of DataStruct are defined for the module. Other modules uses this Type ,,Controller_ObjMod,,.

  • As an enhancement of this module more signals should be used in its interface to outside. Some other connected modules and the test environment will be used them.

  • It may be easy to enhance the given DataStruct organization with the some more signals. But in this case all using modules should be compiled newly, because the data ,,struct,, is changed. But some of the modules are tested already and the developer team cannot spend time to adapted the module. They should be left unchanged.

  • Another story may be: One or some connected modules need a more universal interface. They should be connected to several special incarnations of this module type but with a more universal access. This story is the common approach for using polymorphism in ObjectOrientation. The story above is a story from the practice.

DataStructMng SubSuper appl

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

The left FBlock ,,thizsub,, is the new one. It is a ,,DataStructMng_Inspc,, too which thiz-Output is connected to the 7. input of the otherwise unchanged ,,DataStructMng_Inspc,, right. In the right ''DataStructMng_Inspc''-Fblock there is a checkbox ''inherit'' in the parameter dialog. Because of this connection the left DataStructMng_Inspc receives the Type and the memory amount from the right one, via back writing via the given reference. The left ''DataStructMng_Inspc'' creates the memory for both and assigns the data of the right one as ''superType'', it is inheritance for C++ or a embedded ,,struct,, on start of the sub ,,struct,, for C.

The output pointer refers really 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:

  • ''abstraction'' for a more universal view to a module.

  • ''superType'' for the abstract access.

  • ''subType'' for the implementing data definition

  • ''inheritance'': Usage of a more universal class (module) to build a more specialized comprehensive module.

  • ''derivation'': Describes the relation between a subType and its superType, ''derivation'' and ''inheritance'' are synonym. The inheriting module has the subType.

  • ''Type'' is the C-type of a reference. It means the Type of a class of C++ too.

  • ''class'' is more comprehensive as ''Type''. A class contains the usage as type, and all defined attributes and operations. From view of Graphical Programming a class can consist of more as one function blocks. Each FBlock can present an operation of the class. They can be assembled in a Simulink-library which presents the class.

This terms should be applicated to GraphicalProgramming with Simulink now.

5.4. Example build a comprehensive module or a component

@ident=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'':

  • A ''component'' is a part of an ''application''.

  • A component may consist of ''sub components'' and ''modules''.

  • A ''module'' can contain ''sub modules''. Notice that in Objectorientation a ''subType'' is a more specialized but more comprehensive type as its ''superType'', the more abstract one. Therefore the wording 'superior module' for a more comprehensive or parent module is not used to prevent confusion to the wording 'superType'.

  • The interface to a ''sub module'' can present by a ''subType'' which’s ''superType'' is a more abstract type. The ''sub module'' is contained in its ''parent module''.

  • A ''parent module'' is the module which contains a considered module.

  • A ''function block'' (''Fblock'') is the usage of a module in a Graphical Programming Diagram. The FBlock can be a module which contains some more Graphical connected Fblocks inside, or a module from a library which can present an operation of a class (see chapter above), a standard Simulink Fblock or a Sfunction, which’s content in written in C(++) or maybe as Matlab script.

  • An Fblock can be considered as ''operation''. In conclusion an ''operation'' can be present as ''module''. Of course inside it can call other operations, which are present as FBlocks or sub modules.

  • An ''operation'' is the same as a 'method' in ObjectpOriented slang. The usage of the wording 'operation' instead 'method' is ordinary in UML too.

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.

image:../../../smlk/img/Parent_DataStruct_sample.png|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.

5.5. Example Access to sub modules with Polymorphism

@ident=accessSub

Component C appl

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 [[Topic:.Smlk_Inspc.FB_ObjOConn.appl.emxpl_supersub]. 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 [[Topic:.Smlk_Inspc.FB_ObjOConn.appl.emxpl_supersub]. 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.

In the parameter dialog of the blue controller access FBlock the struct of the name of the parent struct is contained too: ,,(Device_ObjMod*),,. With this information this FBlock checks the type of the left input handle too, hence the ,,checkCast…​,,-FBlock can be saved here.

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.

6. Parameter Dialog for the DataStruct FBlocks

@ident=dataStructPar @date=2020-01-12

6.1. Parameter of FBlock ''DataStructMng_Inspc''

@ident=DataStructMngPar

Parameter of FBs

The '''DataStructMng_Inspc''' has the following parameter:

  • '''filedir - genSource''': Usual you should use a string variable here, not a 'string literal': If the variable contains ,,'',,, an empty string, no header will be generated. This is proper for only simulation, especially on a repeated simulation loop. The String should be set with the ''directory path'' (absolute or relative to the simulink working dir) if the simulation is running before code generation is done. Then a headerfile with the ''Type of DataStruct'' as filename,,.h,, will be written in this directory. It presents a C ,,struct,, with the given connections including access routines (get/set) proper to all connected ''get/set_DataStruct_Inspc'' FBlocks. This header is used for code generation (''Simulink Embedded Coder''). The tlc-File for this FBlock is prepared to include this Header with invocation of the getter and setter instead the FBlock code. Therefore some so name Runtime-Parameter are written internally inside the Simulink data which are used in the tlc-File for target code generation. With them the FBlocks for ''…​DataStruct_Inspc'' are optimized for the target code.

  • ''Type of DataStruct'': This is the name of the created header file and the name of the ,,typedef struct ,, inside the header. It will be used in the generated code. For inspector access this is the type name, not the name of the reference, see FBlock ''add_DataNode_Inspc''.

  • If the checkbox ''inherit'' is set, an additional input (the last if ''chain'' is not set, else before last) is given which should be wired from the first output of another ''DataStructMng_Inspc''-FBlock. That is the sub (more comprehensive) data structure where this dataStruct is member of, a super struct. If this checkbox is not set, no input for that is given.

  • If the checkbox ''chain'' is set, an additional last input for chaining is given. This input should be wired from the only one output of a ''DataStruct_Inspc'' FBlock, which can add more inputs of data.

The number of inputs of usagen of this FBlock depends on the parameter, as shown above with the check boxes and shown below.

  • ''inputs'': It is a free text field but with a well defined syntax. The content will be evaluated on start of the Simulation, it determines the built data struct in memory, its reflection information and the content of the generated header file.

The content of ''inputs'' is parsed with the C implementation of the java class [[srcJava_vishiaBase/org/vishia/util/StringPartScan] which was translated from Java2C. The simple parsing algorithm is manually written contained in ,,emC_Inspc/Inspc_FB/DataStructBase_Inspc.c,, in the operation ,,analyzeVariableDef (…​),,. It can be described with ZBNF-Syntax. The ZBNF parser is not used here, but the syntax definition in ZBNF language shows the parsing algorithm. The ZBNF syntax description language is explained on the fly. It may be intuitive understandable, it is similar BNF (Backus Naur Format) or EBNF:

  • An important difference to EBNF and Xtext is: The terminal symbols are written immediately, not in apostrophes. To suppress confusion between syntax control characters, an transliteration with the ,,\\,, backslash is done like known from C/++ etc.

  • A space in the syntax script can be a white space with comment in the input. To force a space ,,\\ ,, is used (backslash with following space).

  • ,,[…​],, is optional input, ,,[…​|…​],, is a choice (alternatives), ,,[…​|…​|],, means any alternativ, or nothing.

  • ,,{…​.?…​.},, is a repetion with back bough.

  • ,,<subsyntax?semantic>,, represents a sub symbol, ,,<$?semantic>,, is an identifier with the given meaning, ,,<#?number>,, parses a number.

The main syntax is:

inputs::={ <variabledef> ? [ ,<?copyProperties> | ;] } [;].

The inputs consist of several ,,variabledef,, in a loop, separated by ,,, ,, or ,,;,,. A terminating ,, ;,, is optional. If a ,,, ,, is used, the semantic ,,copyProperties,, means that the next variable has all the same ,,variableDef,, properties expect the name. Any variabledef causes one input of the FBlock.

variabledef::= {
   <?mInputInit>
| -<#?accessRights>
| ( <$?structType> * )
| <primitiveChar?type> [{ <#?arraysize>?,}] :
| <$?type> :
| <$?name>
}.

Due to this syntax definition all properties can be written in any oder, it is an alternative in repetition. But a common order should be used.

  • The ,,=,, with the ,,mInputInit,, semantic means, the input for the variable is used only in the init phase to initialize the variable. It is either for handle references (which are wired on initialization as aggregation) or for constant values or for values which are initialized and set by a ''set_DataMng_Inspc'' FBlock.

  • The ,,accessRights,, are discussed in the chapter [[Topic:.Smlk_Inspc.FB_ObjOConn.inspc.]. ,,<#?…​>,, parsers an integer number.

  • The ,,structType,, is written in ,,(…​),, and requires an asterisk ,,*,, on end (adequate pointer-semantic in C)

  • The ,,primitiveChar,, is shown below. After a ,,primitiveChar,, optional some (typical one) ,,arraysize,, as simple number without ,,[..],, but with ,,, ,, as separator can be written. A colon ,,: ,, has to be follow.

  • Alternatively the ,,type,, can be given as identifier also with ,,:,, on end.

  • If the type is missing, it is determined by the input signal type.

  • An identifier without following ,,:,, is the ,,name,,

The standard types (primitives) are written with one char:

primitiveChar::=
 [D <?double>        |F <?float> |J <?int64> |I <?int32> |S <?int16> |B <?int8>
 |d <?double_complex>|f <?float_complex>     |U <?uint32>|W <?uint16>|V <?uint8>
 |j <?int64_complex> |i <?int32_complex> |s <?int16_complex>|b <?int8_complex>
 |Z <?bool>|C <?char8>
 ]

This characters define the in ,,<?semantic>,, shown data types. For Simulink it is ,,float,, for ,,single,,. The shown types are the C-Codegeneration used types.

Examples for that syntax are given in this article in some examples or in the Simulink library as template in the Lib FBlocks.

6.2. Parameter of FBlock ''DataStruct_Inspc''

@ident=DataStructPar

image:../../img/DataStruct_ParamDialg.png|Parameter of DataStruct_Inspc]

It is similar the ''DataStructMng_Inspc'', equal for the inputs field.

The ''unique short sub name'' should be an short identifier for any chain member. It is used on code generation for identifier building for access.

6.3. Parameter of FBlock ''get_DataStruct_Inspc''

@ident=get_DataStructPar

image:../../img/get_DataStruct_ParamDialg.png|Parameter of FBs]

The Dialog for ''get_DataStruct_Inspc'' is similar the other Function Blocks shown in the image above.

  • ''Tstep:'' You should note a numeric variable or a number. It is the step (sample) time of the access. The data are that data from the last execution of the writing FBlock.

  • ''showName'': It is only for the labeling in the model. Often it should be identically with ''Type: Name''.

  • ''Type: Name'' Here the same syntax is valid as for one vairableas in ''inputs'' of a DataStruct_Inspc

    variabledef

    { <?mInputInit> | -<#?accessRights> | ( <$?structType> * ) | <primitiveChar?type> [{ <#?arraysize>?,}] : | <$?type> : | <$?name>{\.<$?name>} }.

The type is necessary here because the type of the output for the model cannot be detected on startup. The ,,accessRights,, are not used here. The ,,structType,, is especially the type of the input, it is tested.

Especially here it is possible to write an access path consisting of more as one ,,name,, separated with ,,.,,. Note: The syntax uses ,,\\.,, because the dot is the end of the syntax definition.

Examples for a element parameter:

  • ,,name,,: Only the name is given. The type of the element comes from the wired connection in the model. It is back propagated here.

  • ,,F2: name,,: The element and the output is a float with 2 elements.

  • ,,F2: (Type*)name,,: The type of the input is the ,,Type,,. This type will be tested in Simulink Tinit Runtime and used for Code generation as pointer type for access (casted from the handle). This is usefull especially for access to a ,,SuperType,, for Polymorphism in DataStruct.

  • ,,OutputType: (Type*)name,,: The output is a handle with the given type.

  • ,,I: aggr.name,,: The ,,aggr,, is the name of an aggregated elements. Either it is an access to data in C-core SFblocks, or an access to references Data in ,,DataStruct,,. The Output is ,,int32,, here.

Note: If a ,,path.,, is given, the access is generated like written. If a path is not given, the generated code use a get routine to access to data inside a DataStruct. The get routine is generated and offered.

7. Connection and Access via Inspector Service

@ident=inspc @date=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 parametrizing 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:

image:../../img/InputValues_Inspc_ServiceInspc.png|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 [[Topic:.Smlk_Inspc.FB_ObjOConn.inspc.].

InputValues Inspc Fields myDevice 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.

InputValues Inspc Fields device

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:

InputValues Inspc Fields deeper

If you have the access password:

image:../../img/InspcGui_PasswordDialog.png|password diaglog]

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

  • 111 till 444 for the 4 access levels, 11 only access, not modify, till 44.

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

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

InputValues Inspc Fields deeper internalData

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.

====Code generation contribution for Simulink Embedded Coder @coder @date=2018-12-09

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.

7.1. Generated code of ,,DataStructMng_Inspc,,-instances

@ident=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';

DataStructMng ParamDialg

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.

InitDataStruct ParamDialg

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);
}

Out DataStruct Inspc Tinit par PID

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.

.
.
.

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.

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.

.
.
.
.

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.

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

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:

  • The block connected on inport 0 is detected, the ,,srcBlock,,.

  • The ,,typeData,, is the parameter ,,name_Refl_param,, of this block. The value of this non-tunable parameter is written to the rtw coder data via the ,,mdlRTW(…​),, routine, see Sfunction-Wrapper.

  • The ,,%<typeData>_s*,, is the pointer type of the input signal, which comes from that source block.

  • It is also the suffix for the ,,get_variable_Type(ptr),, access routine. This access routine is assembled in the tlc code.

  • ,,pData,, is the pointer to the data gotten from the inport handle. The ,,PTR_Handle2Ptr(…​),, converts the handle value on the input to the really pointer. It is the same value (simple macro) for a 32-bit-target system because the handle value on input is the pointer. The macro is important for Accelarator mode which runs in a 64-bit-Environment.

  • ,,LibBlockOutputSignalAddr(0, "", "", 0),, is the destination variable address. This is assigned with the assmebled ,,get_…​(pData),, routine.

  • The ,,get_…​(pData),, routine is generated in the header file, see 1)

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
  • The ,,update,, routine gets the handle, converts to the pointer with a simple macro for the target system because the handle and pointer are equal.

  • The input values are stored only for given names and given connections. If a name is given but a connections is not present in the model, nothing is stores for this attribute, it remains 0.

  • Not used inputs are not generated.