Quantcast

Simulink Code Inspector

Introduction to Simulink Code Inspector

This example shows how to use the Simulink Code Inspector to verify that code generated from models satisfies the source code objectives from DO-178C, Software Considerations in Airborne Systems and Equipment Certification. First, the code for a model hierarchy is automatically generated by Embedded Coder. Next, the generated code is independently verified by Simulink Code Inspector. Finally, an error is purposely introduced into the generated code and then inspected for failure.

Set up a Temporary Folder for Generated Files

Create a temporary folder (in your system's temporary folder) for the build and inspection process. Locally copy the model slcidemo_roll_orig to sldemo_roll so that you can modify it.

currentDir = pwd;
[tempDir, cgDir] = slcidemodir();
load_system('slcidemo_roll_orig')
save_system('slcidemo_roll_orig', 'slcidemo_roll');

About the Model

This model represents a basic roll axis autopilot with two operating modes: roll attitude hold and heading hold. The mode logic for these modes is external to this model. The model architecture represents the heading hold mode and basic roll attitude function as referenced models.

The roll attitude control function is a PID controller that uses roll attitude and roll rate feedback to produce an aileron command. The input to the controller will be either a basic roll angle reference or a roll command to track the desired heading.

Figure 1 shows the top level of the Simulink model.

open_system('slcidemo_roll');

Figure 1: Top-level diagram for the roll axis autopilot model

Figure 2 shows the basic roll angle reference calculation implemented as the virtual subsystem RollAngleReference. Embedded Coder will inline this calculation directly into the main function for slcidemo_roll.

open_system('slcidemo_roll/RollAngleReference');

Figure 2: Virtual subsystem RollAngleReference implementing a roll angle reference

Figure 3 shows the contents of the model HeadingMode, which computes the roll command to track the desired heading. This is a separate model referenced by slcidemo_roll.

close_system('slcidemo_roll/RollAngleReference');
open_system('slcidemo_heading');

Figure 3: Model HeadingMode, which computes the roll command to track desired heading.

Figure 4 shows the contents of the model BasicRollMode, which computes the roll attitude control function. This is a separate model referenced by slcidemo_roll.

close_system('slcidemo_heading');
open_system('slcidemo_attitude');

Figure 4: Model BasicRollMode implementing roll attitude control function (PID)

Prepare the Model for Code Generation and Inspection

Simulink Code Inspector supports a constrained set of modeling semantics and code optimizations. You can use its compatibility checker to determine if a model complies with that constrained set. Compatibility checking and code inspection can be invoked interactively from the main Simulink Code Inspector graphical user interface. This example illustrates how to programmatically automate the overall process of code generation and inspection.

To enable code inspection, the model parameter AdvancedOptControl must be set to the value '-SLCI' on the top level model, slcidemo_roll, which limits the set of optimizations that Embedded Coder employs.

set_param('slcidemo_roll','AdvancedOptControl','-SLCI');

fprintf('\nInvoking compatibility checker ...\n');

config = slci.Configuration('slcidemo_roll');
result = config.checkCompatibility('DisplayResults','None');

for i = 1:numel(result)
    fprintf('\nModel ''%s'' passed %d checks with %d issues.',...
        result{i}.system,...
        result{i}.numPass, result{i}.numWarn + result{i}.numFail)
end
Invoking compatibility checker ...

Model 'slcidemo_roll' passed 46 checks with 0 issues.

Generate Code for the Model

The model is pre-configured to generate code using Embedded Coder. You can generate code implicitly as part of code inspection, however this example illustrates how to split code generation and code inspection into separate steps. Use the method setGenerateCode to specify that the Simulink Code Inspector generates code prior to inspection.

rtwbuild('slcidemo_roll');
### Model reference RTW target (slcidemo_attitude.c) for model slcidemo_attitude is out of date because slcidemo_attitude.c does not exist.
### Starting build procedure for model: slcidemo_attitude
### Successful completion of code generation for model: slcidemo_attitude
### Model reference RTW target (slcidemo_heading.c) for model slcidemo_heading is out of date because slcidemo_heading.c does not exist.
### Starting build procedure for model: slcidemo_heading
### Successful completion of code generation for model: slcidemo_heading
### Starting build procedure for model: slcidemo_roll
### Successful completion of code generation for model: slcidemo_roll

View the generated code in a detailed HTML report, with bi-directional traceability between model and code.

web(fullfile(cgDir,'slcidemo_roll_ert_rtw','html','slcidemo_roll_codegen_rpt.html'))

Code inspection is independent of code generation. Now, configure the model to not regenerate code for the reference models.

set_param('slcidemo_roll','UpdateModelReferenceTargets','AssumeUpToDate');
save_system('slcidemo_roll')

Inspect the Generated Code

Inspect the generated code. By default, Simulink Code Inspector assumes the code has been pre-generated into the default folders where Embedded Coder writes its files. If you want to specify an alternate location, use methods setCodePlacement and setCodeFolder.

In this example, use the method setReportFolder to place the code inspection reports into a local report folder. The method setShowReport specifies if the report is launched automatically. In addition, specify that slcidemo_roll is the top-level model.

config.setTopModel(true);
config.setReportFolder(fullfile('.','report'));
result = config.inspect('DisplayResults','None');
fprintf('Model %s status: %s\n',result.ModelName, result.Status);
 recording macro in il 
 recording macro in il 
Model slcidemo_roll status: PASSED

This example produces a passed result, as expected, which is elaborated in a detailed verification report.

web(fullfile('.', 'report','slcidemo_roll_report.html'));

Inject an Intentional Error into the Code

To show a failed result, introduce an intentional error in the generated code. In this example, change the Logical Operator block inside the RollAngleReference subsystem, Figure 5, in the generated code from an OR operation () to an AND operation (&&). Use the function slcidemo_modifycode.

% Highlight the block for which the code will be modified
hilite_system('slcidemo_roll/RollAngleReference/Or');

% Modify the generated code using a helper function (change || to &&)
cfile = fullfile(cgDir,'slcidemo_roll_ert_rtw','slcidemo_roll.c');
slcidemo_modifycode(cfile,'<S1>/Or','||','&&')
Modified line 52 of file /tmp/slcidemo/slcidemo_roll_ert_rtw/slcidemo_roll.c.
Before:     if ((rtU_Phi >= 6.0F) || (rtU_Phi <= -6.0F)) {
After :     if ((rtU_Phi >= 6.0F) && (rtU_Phi <= -6.0F)) {

Figure 5: Block for which the code is modified to produce an expected error

Code inspection fails to verify because the code no longer matches the model.

result = config.inspect('DisplayResults','None');
fprintf('Model %s status: %s\n',result.ModelName, result.Status);
 recording macro in il 
 recording macro in il 
Model slcidemo_roll status: FAILED

The failure is expected. See the detailed verification report.

[~,h,~]=web(fullfile('.','report','slcidemo_roll_report.html'));

Self-guided Exercise

Try a similar exercise by modifying the model or other aspects of the generated code.

Clean up Example Folders and Files

Close models and remove temporary directories and files.

close_system('slcidemo_roll_orig',0)
close_system('slcidemo_roll',0)
close_system('slcidemo_attitude',0)
close_system('slcidemo_heading',0)
close(h)

cd(currentDir); rmdir(tempDir,'s');