В этом примере показан процесс генерации простого источника (.c
или .cpp
) и заголовок (.h
) файл с использованием примера CFP. Затем он исследует шаблон и код, сгенерированный шаблоном.
Пример шаблона CFP,
, демонстрирует некоторые возможности API шаблона кода, включаяmatlabroot
/ toolbox/rtw/targets/ecoder/example_file_process.tlc
Генерация простого источника (.c
или .cpp
) и заголовок (.h
) файлы
Использование буферов для генерации разделов файла для includes, функций и так далее
Генерация включает, определяет, в стандартные сгенерированные файлы (для примера,
)model
.h
Генерация основного программного модуля
Этот раздел настраивает шаблон CFP и конфигурирует модель, чтобы использовать шаблон при генерации кода. Шаблон генерирует (в дополнение к файлам стандартной модели) исходный файл (timestwo.c
или .cpp
) и заголовочный файл (timestwo.h
).
Выполните следующие действия, чтобы ознакомиться с использованием шаблонов CFP:
Скопируйте пример шаблона CFP,
, в папку за пределами MATLAB® структура папки (то есть не под matlabroot
/ toolbox/rtw/targets/ecoder/example_file_process.tlc
). Если папка находится не в пути MATLAB или в пути TLC, добавьте ее к пути MATLAB. Рекомендуется найти шаблон CFP в той же папке, что и ваш системный целевой файл, который находится в пути TLC.matlabroot
Переименуйте скопированные example_file_process.tlc
на test_example_file_process.tlc
.
Откройте test_example_file_process.tlc
в редактор MATLAB.
Раскомментируйте следующую линию:
%% %assign ERTCustomFileTest = TLC_TRUE
Теперь она гласит:
%assign ERTCustomFileTest = TLC_TRUE
Если ERTCustomFileTest
не назначается как показано, шаблон CFP игнорируется при генерации кода.
Сохраните изменения в файле. Сохраните test_example_file_process.tlc
откройте, чтобы вы могли обратиться к нему позже.
Откройте rtwdemo_udt
модель.
Откройте Simulink® Model Explorer. Выберите активную конфигурацию модели модели и откройте панель < reservedrangesplaceholder0 > активной конфигурации модели.
На вкладке Templates в поле File customization template задайте test_example_file_process.tlc
. Это файл, который вы ранее отредактировали и теперь является заданным шаблоном CFP для вашей модели.
На вкладке General установите флажок Generate code only.
Нажмите Apply.
В окне модели нажмите Ctrl+B. Во время генерации кода заметьте следующее сообщение в Diagnostic Viewer:
Warning: Overriding example ert_main.c!
Это сообщение отображается по причине test_example_file_process.tlc
генерирует основной программный модуль, переопределяя действие по умолчанию целевого устройства ERT. Это объясняется более подробно ниже.
The rtwdemo_udt
Модель сконфигурирована, чтобы сгенерировать отчет о HTML генерации кода. После завершения генерации кода просмотрите отчет.
Заметьте, что список Generated Code содержит следующие файлы:
Под Main file, ert_main.c
.
Под Other files, timestwo.c
и timestwo.h
.
Файлы были сгенерированы шаблоном CFP. В следующем разделе рассматривается шаблон, чтобы узнать, как это было сделано.
Сохраните модель, отчет о генерации кода и test_example_file_process.tlc
файл открыт, чтобы вы могли обратиться к ним в следующем разделе.
В этом разделе рассматриваются выдержки из test_example_file_process.tlc
и часть кода, который он генерирует. См. комментарии в
читая следующую дискуссию.matlabroot
/ rtw/c/tlc/mw/codetemplatelib.tlc
Источник (.c
или .cpp
) и заголовок (.h
) файлы создаются путем вызова LibCreateSourceFile
, как в следующих выдержках:
%assign cFile = LibCreateSourceFile("Source", "Custom", "timestwo") ... %assign hFile = LibCreateSourceFile("Header", "Custom", "timestwo")
Последующий код ссылается на файлы с помощью ссылки на файл, возвращенной из LibCreateSourceFile
.
Шаблон кода API позволяет вам разделить сгенерированный код на каждый файл на разделы, помеченные как Definitions
, Includes
, Functions
, Banner
и так далее. Вы можете добавить код к каждому разделу столько раз, сколько требуется. Этот метод дает вам большую гибкость в форматировании ваших пользовательских файлов кода.
В подразделах, определенных для встроенных разделов, описываются доступные разделы файла и их порядок в сгенерированном файле.
Для каждого раздела сгенерированного файла используйте %openfile
и %closefile
чтобы сохранить текст для этого раздела во временных буферах. Затем, чтобы записать (добавить) содержимое буфера в раздел файла, вызовите LibSetSourceFileSection
, передавая требуемый тег раздела и ссылку на файл. Например, следующий код использует два буфера (typesBuf
и tmpBuf
), чтобы сгенерировать две секции (с тегами "Includes"
и "Functions"
) исходного файла timestwo.c
или .cpp
(ссылка на cFile
):
%openfile typesBuf #include "rtwtypes.h" %closefile typesBuf %<LibSetSourceFileSection(cFile,"Includes",typesBuf)> %openfile tmpBuf /* Times two function */ real_T timestwofcn(real_T input) { return (input * 2.0); } %closefile tmpBuf %<LibSetSourceFileSection(cFile,"Functions",tmpBuf)>
Эти два раздела генерируют всю timestwo.c
или .cpp
файл:
#include "rtwtypes.h" /* Times two function */ FLOAT64 timestwofcn(FLOAT64 input) { return (input * 2.0); }
The timestwo.c
или .cpp
файл, сгенерированный в предыдущем примере, был независимым от стандартных файлов кода, сгенерированного из модели (например
или model
.c.cpp
,
, и так далее). Можно использовать аналогичные методы для генерации пользовательского кода в файлах модели. Шаблон кода API включает функции для получения имен файлов стандартных моделей и другой информации, связанной с моделью. Следующая выдержка вызывает model
.hLibGetMdlPubHdrBaseName
чтобы получить имя для
файл. Затем он получает ссылку на файл и генерирует определение в model
.hDefines
раздел
:model
.h
%% Add a #define to the model's public header file model.h %assign pubName = LibGetMdlPubHdrBaseName() %assign modelH = LibCreateSourceFile("Header", "Simulink", pubName) %openfile tmpBuf #define ACCELERATION 9.81 %closefile tmpBuf %<LibSetSourceFileSection(modelH,"Defines",tmpBuf)>
Исследуйте сгенерированные rtwdemo_udt.h
файл для просмотра сгенерированных #define
директива.
Обычно цель ERT определяет, следует ли и как сгенерировать ert_main.c
или .cpp
модуль на основе настроек Generate a example main program и опций Target operating system на панели Templates диалогового окна Параметры Конфигурации. Можно использовать шаблон CFP, чтобы переопределить нормальное поведение и сгенерировать основной программный модуль, настроенный для вашего целевого окружения.
Для поддержки генерации основных программных модулей предусмотрены два файла TLC:
bareboard_srmain.tlc
: Код TLC, чтобы сгенерировать пример односкоростного основного программного модуля для целевого окружения barebard. Код генерируется одной функцией TLC, FcnSingleTaskingMain
.
bareboard_mrmain.tlc
: Код TLC для генерации многоразового основного программного модуля для целевого окружения barebard. Код генерируется одной функцией TLC, FcnMultiTaskingMain
.
В примере файл шаблона CFP
следующий код генерирует либо одну, либо многозадачность matlabroot
/ toolbox/rtw/targets/ecoder/example_file_process.tlcert_main.c
или .cpp
модуль. Логика зависит от информации, полученной из шаблона кода вызовов API LibIsSingleRateModel
и LibIsSingleTasking
:
%% Create a simple main. Files are located in MATLAB/rtw/c/tlc/mw. %if LibIsSingleRateModel() || LibIsSingleTasking() %include "bareboard_srmain.tlc" %<FcnSingleTaskingMain()> %else %include "bareboard_mrmain.tlc" %<FcnMultiTaskingMain()> %endif
Обратите внимание, что bareboard_srmain.tlc
и bareboard_mrmain.tlc
используйте шаблон кода API, чтобы сгенерировать ert_main.c
или .cpp
.
При генерации собственного основного программного модуля вы отключаете генерацию ert_main.c
по умолчанию или
.cpp
. Переменная TLC GenerateSampleERTMain
управляет генерацией ert_main.c
или .cpp
. Можно непосредственно заставить эту переменную TLC_FALSE
. Примеры bareboard_mrmain.tlc
и bareboard_srmain.tlc
использовать этот метод, как показано на следующем выдержке из bareboard_srmain.tlc
.
%if GenerateSampleERTMain %assign CompiledModel.GenerateSampleERTMain = TLC_FALSE %warning Overriding example ert_main.c! %endif
Кроме того, можно реализовать SelectCallback
функция для вашей цели. A SelectCallback
функция является функцией MATLAB, которая запускается при:
Загрузите модель.
Обновите все настройки строения в диалоговом окне Параметров конфигурации.
Создайте модель.
Ваши SelectCallback
функция должна отменить выбор и отключить опцию Сгенерировать пример основной программы. Это препятствует переменной TLC GenerateSampleERTMain
от установки в TLC_TRUE.
Смотрите раздел структуры rtwgensettings для получения информации о создании SelectCallback
функция.
Следующий код иллюстрирует, как отменить выбор и отключить опцию Generate a example main program в контексте SelectCallback
функция.
slConfigUISetVal(hDlg, hSrc, 'GenerateSampleERTMain', 'off'); slConfigUISetEnabled(hDlg, hSrc, 'GenerateSampleERTMain',0); hSrc.refreshDialog;
Примечание
Создание основной программы для вашего целевого окружения требует некоторой индивидуальной настройки; например, в среде barebard необходимо прикрепить rt_OneStep
к прерыванию таймера. Ожидается, что вы будете настраивать либо сгенерированный код, либо генерирующий TLC код, либо и то, и другое. Для получения дополнительной информации см. Руководство по изменению основной программы и Руководство по изменению rt_OneStep.
Можно задать пользовательские лексемы в файле CGT и непосредственно сгенерированный код в связанный встроенный раздел. Эта функция дает вам дополнительный контроль над форматированием кода в каждом встроенном разделе. Например, можно добавить подсекции во встроенные сечения, которые еще не определяют подсекции. Пользовательские разделы должны быть связаны с одним из встроенных разделов: Includes
, Defines
, Types
, Enums
, Definitions
, Declarations
, или Functions
. Чтобы создать пользовательские разделы, вы должны
Добавьте пользовательскую лексему в раздел вставки кода файла CGT.
В файле CFP:
Соберите код, который будет сгенерирован в пользовательский раздел, в буфер.
Объявите связь между пользовательским разделом и встроенным разделом с функцией API шаблона кода LibAddSourceFileCustomSection
.
Эмитируйте код в пользовательский раздел с функцией API шаблона кода LibSetSourceFileCustomSection
.
Следующие примеры кода иллюстрируют сложение пользовательской лексемы, Myincludes
, в файл CGT и последующую ассоциацию пользовательского раздела Myincludes
со встроенной секцией Includes
в файле CFP.
Примечание
Если вы еще не создали пользовательские файлы CGT и CFP для вашей модели, скопируйте файлы шаблона по умолчанию
и matlabroot
/ toolbox/rtw/targets/ecoder/ert_code_template.cgt
в рабочую папку, которая находится вне структуры папки MATLAB, но в пути MATLAB или TLC, переименуйте их (для примера добавьте префикс matlabroot
/ toolbox/rtw/targets/ecoder/example_file_process.tlctest_
к каждому файлу) и обновляйте панель Templates диалогового окна Параметры конфигурации (Configuration Parameters), чтобы ссылаться на них.
Сначала добавьте лексему Myincludes
в раздел вставки кода файла CGT. Для примера:
%<Includes> %<Myincludes> %<Defines> %<Types> %<Enums> %<Definitions> %<Declarations> %<Functions>
Далее в файле CFP добавьте код для генерации include
директивы в буфер. Например, в вашей копии примера файла CFP можно вставить следующий раздел между Includes
раздел и Create a simple main
раздел:
%% Add a custom section to the model's C file model.c %openfile tmpBuf #include "moretables1.h" #include "moretables2.h" %closefile tmpBuf %<LibAddSourceFileCustomSection(modelC,"Includes","Myincludes")> %<LibSetSourceFileCustomSection(modelC,"Myincludes",tmpBuf)>
LibAddSourceFileCustomSection
вызов функции объявляет связь между встроенной секцией Includes
и пользовательский раздел Myincludes
. Myincludes
является подразделом Includes
. The LibSetSourceFileCustomSection
вызов функции направляет код в tmpBuf
буфер к Myincludes
раздел сгенерированного файла. LibSetSourceFileCustomSection
синтаксически идентичен LibSetSourceFileSection
.
В сгенерированном коде директивы включения, сгенерированные в пользовательский раздел, появляются после другого кода, направленного на Includes
.
#include "rtwdemo_udt.h" #include "rtwdemo_udt_private.h" /* #include "mytables.h" */ #include "moretables1.h" #include "moretables2.h"
Примечание
Размещение пользовательской лексемы в этом примере файла CGT произвольно. Путем определения местоположения %<Myincludes>
после %<Includes>
Файл CGT задает только то, что Myincludes
код появляется после Includes
код.
Пользовательские лексемы автоматически преобразуются в синтаксис TLC как часть процесса сборки. Чтобы избежать лексемы, то есть подготовить его к обычному расширению TLC, используйте символ '!'. Для примера, лексема %<!TokenName>
расширен до %<TokenName>
программой преобразования шаблонов. Можно задать действительный код TLC, включая вызовы функций TLC: %<!MyTLCFcn()>
.
Пользовательские лексемы не поддерживаются при генерации кода С++.