Для создания полностью встроенных C MEX S-функций для устаревшего или пользовательского кода можно использовать инструмент кода Simulink ® Legacy Code Tool. S-функции оптимизированы для встраиваемых компонентов, таких как драйверы устройств и таблицы поиска, и они вызывают существующие функции C или C++.
Примечание
Legacy Code Tool может взаимодействовать с функциями C++, но не с объектами C++. Чтобы обойти эту проблему, чтобы инструмент мог взаимодействовать с объектами C++, см. раздел Ограничения устаревших инструментов кода.
Инструмент можно использовать для:
Если требуется включить эти типы S-функций в модели, для которых предполагается создать код, используйте инструмент для создания файла блока TLC. Файл блока TLC указывает, как созданный код для модели вызывает существующую функцию C или C++.
Если S-функция зависит от файлов в папках, отличных от папки, содержащей динамически загружаемый исполняемый файл S-функции, используйте инструмент для создания sFunction_makecfg.m или rtwmakecfg.m файл для S-функции. При создании файла эти зависимости сохраняются при построении модели, включающей S-функцию. Например, для некоторых приложений, таких как пользовательские конечные объекты, может потребоваться найти файлы в определенном расположении. Процесс построения ищет sFunction_makecfg.m или rtwmakecfg.m в той же папке, что и динамически загружаемый исполняемый файл S-функции, и вызывает функцию в файле.
Дополнительные сведения см. в разделе Интеграция функций C с помощью устаревшего инструмента кода.
В зависимости от требований к созданию кода приложения для создания кода модели, использующей S-функцию, выполните одно из следующих действий:
Создать один .cpp для встроенной S-функции. В структуре данных Legacy Code Tool задайте значение Options.singleCPPMexFile поле в true перед созданием исходного файла S-функции из существующей функции C. Например:
def.Options.singleCPPMexFile = true;
legacy_code('sfcn_cmex_generate', def);Создайте исходный файл и файл блока TLC для встроенной S-функции. Например:
def.Options.singleCPPMexFile = false;
legacy_code('sfcn_cmex_generate', def);
legacy_code('sfcn_tlc_generate', def);Вы не можете установить singleCPPMexFile поле в true если
Options.language='C++'
Один из следующих объектов Simulink используется с IsAlias свойство имеет значение true:
Simulink.Bus
Simulink.AliasType
Simulink.NumericType
Спецификация функции Legacy Code Tool включает void* или void** для представления скалярных рабочих данных для аргумента состояния
HeaderFiles поле в структуре «Устаревший инструмент кода» определяет несколько заголовочных файлов
Чтобы применить параметры конфигурации модели для стиля кода к устаревшей функции:
Инициализируйте структуру данных Legacy Code Tool. Например:
def = legacy_code('initialize');
В структуре данных задайте значение Options.singleCPPMexFile поле в true. Например:
def.Options.singleCPPMexFile = true;
Для проверки настройки введите:
def.Options.singleCPPMexFile
Вы не можете установить singleCPPMexFile поле в true если
Options.language='C++'
Один из следующих объектов Simulink используется с IsAlias свойство имеет значение true:
Simulink.Bus
Simulink.AliasType
Simulink.NumericType
Спецификация функции Legacy Code Tool включает void* или void** для представления скалярных рабочих данных для аргумента состояния
HeaderFiles поле в структуре «Устаревший инструмент кода» определяет несколько заголовочных файлов
По умолчанию инструмент кода предыдущей версии предполагает, что файлы, от которых зависит S-функция, находятся в той же папке, что и динамически загружаемый исполняемый файл для S-функции. Если функция S зависит от файлов, которые находятся в другом месте, и вы используете процесс создания файла шаблона, создайте sFunction_makecfg.m или rtwmakecfg.m файл для S-функции. Например, этот файл может быть создан, если структура данных прежнего инструмента кода определяет ресурсы компиляции как имена путей.
Для создания sFunction_makecfg.m или rtwmakecfg.m файл, вызовите legacy_code функция с 'sfcn_makecfg_generate' или 'rtwmakecfg_generate' в качестве первого аргумента и имя структуры данных Legacy Code Tool в качестве второго аргумента. Например:
legacy_code('sfcn_makecfg_generate', lct_spec);Если вы используете несколько файлов регистрации в одной папке и генерируете S-функцию для каждого файла с одним вызовом legacy_code, вызов legacy_code который определяет 'sfcn_makecfg_generate' или 'rtwmakecfg_generate' должен быть общим для всех файлов регистрации. Дополнительные сведения см. в разделе Обработка нескольких файлов регистрации.
Например, при определении defs в качестве массива устаревших структур инструментов кода вызывается legacy_code с 'sfcn_makecfg_generate' один раз.
defs = [defs1(:);defs2(:);defs3(:)];
legacy_code('sfcn_makecfg_generate', defs);Дополнительные сведения см. в разделе Поддержка сборки S-функций.
Можно развернуть S-функции, создаваемые с помощью средства устаревшего кода, чтобы их могли использовать другие пользователи. Чтобы развернуть S-функцию для моделирования и создания кода, совместно используйте следующие файлы:
Регистрационный файл
Компилированный динамически загружаемый исполняемый файл
Файл блока TLC
sFunction_makecfg.m или rtwmakecfg.m файл
Заголовок, источник и включаемые файлы, от которых зависит сгенерированная S-функция
При использовании этих развернутых файлов:
Перед использованием развернутых файлов в модели Simulink добавьте папку, содержащую файлы S-функций, в путь MATLAB ®.
Если структура данных прежнего инструмента кода регистрирует требуемые файлы как абсолютные пути, и местоположение файлов изменяется, выполните регенерацию sFunction_makecfg.m или rtwmakecfg.m файл.
Legacy Code Tool может взаимодействовать с функциями C++, но не с объектами C++. Используя предыдущий пример в качестве отправной точки, вот пример того, как можно обойти это ограничение.
Изменение определения класса для adder в новом файле adder_cpp.hpp. Добавить три новых макроса, которые динамически распределяют новый 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-функция управляет своей собственной 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 adder объект указателя.
def.OutputFcnSpec = 'int32 y1 = adderOutput(void *work1, int32 u1)';
TerminateFcnSpec вызывает макрос, освобождающий память.
def.TerminateFcnSpec = 'deleteAdder(void **work1)';