В этом примере показан процесс генерации простого источника (.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()>.
Пользовательские лексемы не поддерживаются при генерации кода С++.