使用代码继承工具在生成的代码中导入对外部代码的调用
代码继承工具和代码生成
您可以使用 Simulink® 代码继承工具为现有代码或自定义代码生成完全内联的 C MEX S-Function。S-Function 针对设备驱动程序和查找表等嵌入式组件进行了优化,可以调用现有的 C 或 C++ 函数。
注意
代码继承工具可与 C++ 函数对接,但不能与 C++ 对象对接。要解决此问题,使该工具能够与 C++ 对象对接,请参阅Legacy Code Tool Limitations。
可以使用该工具:
编译和构造生成的 S-Function 以进行仿真。
生成封装的 S-Function 模块,此模块被配置为调用现有的外部代码。
如果要在打算为其生成代码的模型中包含这些类型的 S-Function,请使用该工具生成 TLC 模块文件。TLC 模块文件指定为模型生成的代码如何调用现有的 C 或 C++ 函数。
如果 S-Function 依赖的是其他文件夹中的文件,而不是包含 S-Function 动态加载的可执行文件的文件夹中的文件,请使用该工具为 S-Function 生成 sFunction
_makecfg.m
或 rtwmakecfg.m
文件。生成这样的文件可在编译包含 S-Function 的模型时保持这些依存关系。例如,对于某些应用程序(如自定义目标),您可能希望在目标特定的位置找到文件。编译过程将在与 S-Function 动态加载可执行文件相同的文件夹中查找 sFunction
_makecfg.m
或 rtwmakecfg.m
,并调用此文件中的函数。
有关详细信息,请参阅Integrate C Functions Using Legacy Code Tool。
生成内联 S-Function 文件以进行代码生成
要为使用 S-Function 的模型生成代码,请根据应用程序的代码生成要求执行以下操作之一:
为内联 S-Function 生成一个
.cpp
文件。在从现有 C 函数生成 S-Function 源文件之前,请在代码继承工具数据结构体中将Options.singleCPPMexFile
字段的值设置为true
。例如:def.Options.singleCPPMexFile = true; legacy_code('sfcn_cmex_generate', def);
为内联 S-Function 生成源文件和 TLC 模块文件。例如:
def.Options.singleCPPMexFile = false; legacy_code('sfcn_cmex_generate', def); legacy_code('sfcn_tlc_generate', def);
有关 singleCPPMexFile 的限制
在下列情况下,不能将 singleCPPMexFile
字段设置为 true
:
Options.language='C++'
您使用以下 Simulink 对象之一并将
IsAlias
属性设置为true
:Simulink.Bus
Simulink.AliasType
Simulink.NumericType
代码继承工具函数规范中包含
void*
或void**
,以表示状态参数的标量工作数据代码继承工具结构体的
HeaderFiles
字段指定多个头文件
对已有函数应用代码样式设置
要将代码样式的模型配置参数应用于已有函数,请执行以下操作:
初始化代码继承工具数据结构体。例如:
def = legacy_code('initialize');
在数据结构体中,将
Options.singleCPPMexFile
字段的值设置为true
。例如:def.Options.singleCPPMexFile = true;
要检查设置,请输入:
def.Options.singleCPPMexFile
有关 singleCPPMexFile 的限制
在下列情况下,不能将 singleCPPMexFile
字段设置为 true
:
Options.language='C++'
您使用以下 Simulink 对象之一并将
IsAlias
属性设置为true
:Simulink.Bus
Simulink.AliasType
Simulink.NumericType
代码继承工具函数规范中包含
void*
或void**
,以表示状态参数的标量工作数据代码继承工具结构体的
HeaderFiles
字段指定多个头文件
解决对不同位置的文件的依存关系
默认情况下,代码继承工具假定 S-Function 所依赖的文件与 S-Function 的动态加载可执行文件位于同一个文件夹中。如果您的 S-Function 所依赖的文件位于其他位置,而您使用的是模板联编文件编译过程,请为 S-Function 生成一个 sFunction
_makecfg.m
或 rtwmakecfg.m
文件。例如,如果您的代码继承工具数据结构体将编译资源定义为路径名称,则您可能需要生成此文件。
要生成 sFunction
_makecfg.m
或 rtwmakecfg.m
文件,请调用 legacy_code
函数,并将 'sfcn_makecfg_generate'
或 'rtwmakecfg_generate'
作为第一个参数,将代码继承工具数据结构体的名称作为第二个参数。例如:
legacy_code('sfcn_makecfg_generate', lct_spec);
如果您使用同一个文件夹中的多个注册文件,并通过调用一次 legacy_code
为每个文件生成一个 S-Function,则指定 'sfcn_makecfg_generate'
或 'rtwmakecfg_generate'
的 legacy_code
调用必须对所有注册文件都是通用的。有关详细信息,请参阅Handling Multiple Registration Files。
例如,如果将 defs
定义为代码继承工具结构体数组,则可以使用 'sfcn_makecfg_generate'
调用一次 legacy_code
。
defs = [defs1(:);defs2(:);defs3(:)]; legacy_code('sfcn_makecfg_generate', defs);
有关详细信息,请参阅编译对 S-Function 的支持。
部署 S-Function 以进行仿真和代码生成
您可以部署使用代码继承工具生成的 S-Function,以便其他人也能使用它们。要部署 S-Function 进行仿真和代码生成,请共享以下文件:
注册文件
已编译的动态加载可执行文件
TLC 模块文件
sFunction
_makecfg.m
或rtwmakecfg.m
文件生成的 S-Function 所依赖的头文件、源文件和 include 文件
使用这些部署的文件时:
在 Simulink 模型中使用部署的文件之前,请将包含 S-Function 文件的文件夹添加到 MATLAB® 路径中。
如果代码继承工具数据结构体将所需的文件注册为绝对路径,而文件位置发生改变,请重新生成
sFunction
_makecfg.m
或rtwmakecfg.m
文件。
集成外部 C++ 对象
代码继承工具可与 C++ 函数对接,但不能与 C++ 对象对接。以上一个示例为基础,下面的示例说明如何应对这一限制。
在新文件
adder_cpp.hpp
中修改adder
的类定义。添加三个新的宏,分别用于动态分配新的adder
对象,调用add_one()
方法和释放分配的内存。每个宏通过一个指针指向一个adder
对象。因为代码继承工具调用的每个函数必须具有一个与 C 语言类似的签名,所以该指针以void*
的形式进行缓存和传递。因此,您必须在宏中明确转换为adder*
。adder
的新类定义:#ifndef _ADDER_CPP_ #define _ADDER_CPP_ class adder { private: int int_state; public: adder(): int_state(0) {}; int add_one(int increment); int get_val() {return int_state;}; }; // Method wrappers implemented as macros #define createAdder(work1) \ *(work1) = new adder #define deleteAdder(work1) \ delete(static_cast<adder*>(*(work1))) #define adderOutput(work1, u1) \ (static_cast<adder*> ((work1)))->add_one(u1) #endif /* _ADDER_CPP_ */
更新
adder_cpp.cpp
。采用类修改方式(而不是一个全局实例),生成的每个 S-Function 可以管理其自己的adder
对象。#include "adder_cpp.hpp" int adder::add_one(int increment) { int_state += increment; return int_state; }
使用以下更改更新
rtwdemo_sfun_adder_cpp.cpp
:StartFcnSpec
调用的宏负责分配新的adder
对象并缓存指针。def.StartFcnSpec = 'createAdder(void **work1)';
OutputFcnSpec
调用的宏负责调用add_one()
方法并提供 S-Function 特定的adder
指针对象。def.OutputFcnSpec = 'int32 y1 = adderOutput(void *work1, int32 u1)';
TerminateFcnSpec
调用的宏负责释放内存。def.TerminateFcnSpec = 'deleteAdder(void **work1)';