%% Internal Data in the Generated Code
% This example shows how the generated code stores internal data such as
% block states.
%% Explore Example Model
% Open the example model |rtwdemo_roll|.
open_system('rtwdemo_roll')
%%
% The model contains internal signals that do not connect to root-level
% Inport or Outport blocks. Some of the signals have a name, such as the
% |phiCmd| signal.
%
% The model also contains some blocks that maintain state data. For
% example, in the |BasicRollMode| subsystem, a Discrete-Time Integrator
% block labeled |Integrator|
% maintains a state.
%
% In the model, set *Configuration Parameters > Code Generation > System
% target file* to |grt.tlc|.
set_param('rtwdemo_roll','SystemTargetFile','grt.tlc')
%%
% Inspect the setting for *Configuration Parameters > Code Generation >
% Interface > Code interface packaging*. The setting |Nonreusable function|
% means that the generated code is not reusable (reentrant).
%
% For this example, generate simpler code by clearing *Configuration
% Parameters > Code Generation > Interface > Advanced parameters > Mat-file
% logging*.
set_param('rtwdemo_roll','MatFileLogging','off')
%% Generate Nonreusable Code
% Set these
% configuration parameters:
%
% * Set *Default parameter behavior* to |Tunable|.
% * Clear *Signal storage reuse*.
set_param('rtwdemo_roll','DefaultParameterBehavior','Tunable',...
'OptimizeBlockIOStorage','off')
%%
% Generate code from the model.
rtwbuild('rtwdemo_roll')
%%
% The file |rtwdemo_roll.h| defines several structure types that
% represent internal data. For example, the block input and output
% structure defines one field for each internal signal in the model. Each
% field name derives from the name of the block that generates the signal
% or, if you specify a name for the signal, from the name of the signal.
file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.h');
rtwdemodbtype(file,...
'/* Block signals (default storage) */','} B_rtwdemo_roll_T;',1,1)
%%
% The file defines a structure type, the DWork structure, to represent block
% states such as the state of the Discrete-Time Integrator block.
rtwdemodbtype(file,...
'/* Block states (default storage) for system','} DW_rtwdemo_roll_T;',1,1)
%%
% The file defines a structure type to represent parameter data. Each
% tunable block parameter in the model, such as the *Gain* parameter of a
% Gain block, appears as a field of this structure. If a block parameter
% acquires its value from a MATLAB variable or a |Simulink.Parameter|
% object, the variable or object appears as a field, not the block
% parameter.
%
% The file also defines a structure type, the _real-time model data
% structure_, whose single field represents a run-time indication of whether the
% generated code has encountered an error during execution.
rtwdemodbtype(file,'/* Real-time Model Data Structure */',...
'/* Block parameters (default storage) */',1,0)
%%
% For the structure type that represents the real-time model data
% structure, the file |rtwdemo_roll_types.h| creates an alias that the
% generated code later uses to allocate memory for the structure.
file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll_types.h');
rtwdemodbtype(file,'/* Forward declaration for rtModel */',...
'RT_MODEL_rtwdemo_roll_T;',1,1)
%%
% Using these structure types, the file |rtwdemo_roll.c| defines (allocates memory for) global structure
% variables that store internal data for the generated algorithm. The file
% also defines variables that represent the real-time model data structure
% and a pointer to the structure.
file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.c');
rtwdemodbtype(file,'/* Block signals (default storage) */',...
'= &rtwdemo_roll_M_;',1,1)
%%
% The model |step| function, which represents the primary model algorithm,
% uses a |void void| interface (with no arguments).
rtwdemodbtype(file,...
'/* Model step function */','void rtwdemo_roll_step(void)',1,1)
%%
% In the function definition, the algorithm performs calculations and
% stores intermediate results in the signal and state structures by
% directly accessing the global variables. The algorithm also reads
% parameter data from the corresponding global variable. For example, in
% the |BasicRollMode| subsystem, the code generated for the |Integrator|
% block reads and writes signal, state, and parameter data from the structures.
rtwdemodbtype(file,'/* DiscreteIntegrator: ''<S1>/Integrator'' *',...
'/* End of DiscreteIntegrator: ''<S1>/Integrator'' */',1,1)
%%
% Due to the |void void| interface and the direct data access, the function
% is not reentrant. If you call the function multiple times in an
% application, each call writes data to the global structure variables and
% the subsequent call can read that data, resulting in unintentional
% interference between the calls.
%
% The model initialization function |rtwdemo_roll_initialize| initializes
% all of the internal data to zero. The function also initializes the error
% status by calling a specialized macro function. The initialization
% function directly accesses the global variables, which means that the function is not
% reentrant.
rtwdemodbtype(file,'/* Model initialize function */',...
'sizeof(DW_rtwdemo_roll_T));',1,1)
%%
% The function then initializes the block states in the DWork structure to the initial values that
% the block parameters in the model specify. Two of the three states in the
% model have
% tunable initial values, so the code initializes them by reading
% data from the parameters structure.
rtwdemodbtype(file,...
'/* SystemInitialize for Atomic SubSystem: ''<Root>/RollAngleReference'' */',...
'/* Model terminate function */',1,0)
%% Generate Reusable Code
% You can configure the generated code as reentrant, which means you can
% call the entry-point functions multiple times in an application. With
% this configuration, instead of directly accessing global variables, the
% entry-point functions accept internal data through formal parameters
% (pointer arguments). With these pointer arguments, each call can maintain internal data
% in a set of separate global variables, preventing unintentional interaction between the
% calls.
%
% In the model, set *Configuration Parameters > Code Generation > Interface
% > Code interface packaging* to |Reusable function|.
set_param('rtwdemo_roll','CodeInterfacePackaging','Reusable function')
%%
% Generate code from the model.
rtwbuild('rtwdemo_roll')
%%
% Now, in |rtwdemo_roll.h|, the real-time model data structure contains pointers to
% the error indication, the internal data, and primary input and output data
% in the form of |ExtU| and |ExtY| substructures (the fields of which represent
% Inport and Outport blocks at the root level of the model).
file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.h');
rtwdemodbtype(file,'/* Real-time Model Data Structure */',...
'/* External data declarations for dependent source files */',1,0)
%%
% To call the generated code multiple times in an application, your code
% must allocate memory for a real-time model data structure per call.
% The file |rtwdemo_roll.c| defines a specialized function that allocates
% memory for a new real-time model data structure and returns a pointer to the structure.
% The function also allocates memory for
% the substructures
% that the fields in the model data structure point to, such as the DWork structure.
file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.c');
rtwdemodbtype(file,'/* Model data allocation function */',...
'RT_MODEL_rtwdemo_roll_T *rtwdemo_roll(void)',1,1)
%%
% The model |step| function accepts an argument that represents the real-time model data structure.
rtwdemodbtype(file,'/* Model step function */','void rtwdemo_roll_step',1,1)
%%
% In the function definition, the algorithm first extracts each pointer from
% the real-time model data structure into a local variable.
rtwdemodbtype(file,'*rtwdemo_roll_B =','rtwdemo_roll_M->outputs;',1,1)
%%
% Then, to access the
% internal data stored in global memory, the algorithm interacts with these local variables.
rtwdemodbtype(file,'/* DiscreteIntegrator: ''<S1>/Integrator'' */',...
'/* End of DiscreteIntegrator: ''<S1>/Integrator'' */',1,1)
%%
% Similarly, the model initialization function accepts the real-time model
% data structure as an argument.
rtwdemodbtype(file,...
'/* Model initialize function */','void rtwdemo_roll_initialize',1,1)
%%
% Because each call that you make to an entry-point function interacts with a separate
% real-time model data structure, you avoid unintentional interaction
% between the calls.
%% Eliminate Internal Data with Code Generation Optimizations
% For more efficient code that consumes less memory, select the
% optimizations, such as *Default parameter behavior*, that you cleared
% earlier.
set_param('rtwdemo_roll','DefaultParameterBehavior','Inlined',...
'OptimizeBlockIOStorage','on',...
'LocalBlockOutputs','on')
%%
% In this example, for simpler code, set *Code interface packaging* to |Nonreusable
% function|.
set_param('rtwdemo_roll','CodeInterfacePackaging','Nonreusable function')
%%
% Generate code from the model.
rtwbuild('rtwdemo_roll')
%%
% Now, |rtwdemo_roll.h| does not define a structure for block inputs and
% outputs. For all of the internal signals in the model, the optimizations
% either eliminated storage or created local function variables instead of
% global structure fields.
%
% The optimizations were not able to eliminate storage for the three block states, so
% the file continues to define the DWork structure type.
file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.h');
rtwdemodbtype(file,...
'/* Block states (default storage) for system','} DW_rtwdemo_roll_T;',1,1)
%%
% The code generated for the Discrete-Time Integrator block now stores
% state and output data only in the DWork structure.
file = fullfile('rtwdemo_roll_grt_rtw','rtwdemo_roll.c');
rtwdemodbtype(file,'/* Update for DiscreteIntegrator: ''<S1>/Integrator''',...
'/* End of Update for DiscreteIntegrator: ''<S1>/Integrator'' */',1,1)
%%
% The optimizations also eliminated storage for the block parameters in the
% model. For example, in the Discrete-Time Integrator block, the *Upper
% saturation limit* and *Lower saturation limit* parameters are set to
% |intLim| and |-intLim|. |intLim| is a |Simulink.Parameter| object
% that stores the value |5|. In the code generated for the Discrete-Time Integrator, these block parameters and
% |intLim| appear as inlined literal numbers |5.0F| and |-5.0F|.
%
% If a model contains a parameter that the code generator cannot inline directly
% (for example, an array parameter), the code defines a structure type
% that represents the data. This _constant parameters_ structure uses the
% |const| storage type qualifier, so some build toolchains can optimize the
% assembly code further.

% Copyright 2019 The MathWorks, Inc.