Сгенерируйте исходные файлы и файлы заголовков с помощью пользовательского шаблона обработки файлов (CFP)

В этом примере показан процесс генерации простого источника (.c или .cpp) и заголовок (.h) файл с использованием примера CFP. Затем он исследует шаблон и код, сгенерированный шаблоном.

Пример шаблона CFP, matlabroot/ toolbox/rtw/targets/ecoder/example_file_process.tlc, демонстрирует некоторые возможности API шаблона кода, включая

  • Генерация простого источника (.c или .cpp) и заголовок (.h) файлы

  • Использование буферов для генерации разделов файла для includes, функций и так далее

  • Генерация включает, определяет, в стандартные сгенерированные файлы (для примера, model.h)

  • Генерация основного программного модуля

Сгенерируйте код с шаблоном CFP

Этот раздел настраивает шаблон CFP и конфигурирует модель, чтобы использовать шаблон при генерации кода. Шаблон генерирует (в дополнение к файлам стандартной модели) исходный файл (timestwo.c или .cpp) и заголовочный файл (timestwo.h).

Выполните следующие действия, чтобы ознакомиться с использованием шаблонов CFP:

  1. Скопируйте пример шаблона CFP, matlabroot/ toolbox/rtw/targets/ecoder/example_file_process.tlc, в папку за пределами MATLAB® структура папки (то есть не под matlabroot). Если папка находится не в пути MATLAB или в пути TLC, добавьте ее к пути MATLAB. Рекомендуется найти шаблон CFP в той же папке, что и ваш системный целевой файл, который находится в пути TLC.

  2. Переименуйте скопированные example_file_process.tlc на test_example_file_process.tlc.

  3. Откройте test_example_file_process.tlc в редактор MATLAB.

  4. Раскомментируйте следующую линию:

    %%  %assign ERTCustomFileTest = TLC_TRUE

    Теперь она гласит:

      %assign ERTCustomFileTest = TLC_TRUE

    Если ERTCustomFileTest не назначается как показано, шаблон CFP игнорируется при генерации кода.

  5. Сохраните изменения в файле. Сохраните test_example_file_process.tlc откройте, чтобы вы могли обратиться к нему позже.

  6. Откройте rtwdemo_udt модель.

  7. Откройте Simulink® Model Explorer. Выберите активную конфигурацию модели модели и откройте панель < reservedrangesplaceholder0 > активной конфигурации модели.

  8. На вкладке Templates в поле File customization template задайте test_example_file_process.tlc. Это файл, который вы ранее отредактировали и теперь является заданным шаблоном CFP для вашей модели.

  9. На вкладке General установите флажок Generate code only.

  10. Нажмите Apply.

  11. В окне модели нажмите Ctrl+B. Во время генерации кода заметьте следующее сообщение в Diagnostic Viewer:

    Warning:  Overriding example ert_main.c!
    

    Это сообщение отображается по причине test_example_file_process.tlc генерирует основной программный модуль, переопределяя действие по умолчанию целевого устройства ERT. Это объясняется более подробно ниже.

  12. The rtwdemo_udt Модель сконфигурирована, чтобы сгенерировать отчет о HTML генерации кода. После завершения генерации кода просмотрите отчет.

    Заметьте, что список Generated Code содержит следующие файлы:

    • Под Main file, ert_main.c.

    • Под Other files, timestwo.c и timestwo.h.

    Файлы были сгенерированы шаблоном CFP. В следующем разделе рассматривается шаблон, чтобы узнать, как это было сделано.

  13. Сохраните модель, отчет о генерации кода и test_example_file_process.tlc файл открыт, чтобы вы могли обратиться к ним в следующем разделе.

Анализ примера шаблона CFP и сгенерированного кода

В этом разделе рассматриваются выдержки из 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, model.h, и так далее). Можно использовать аналогичные методы для генерации пользовательского кода в файлах модели. Шаблон кода API включает функции для получения имен файлов стандартных моделей и другой информации, связанной с моделью. Следующая выдержка вызывает LibGetMdlPubHdrBaseName чтобы получить имя для model.h файл. Затем он получает ссылку на файл и генерирует определение в Defines раздел 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.tlcследующий код генерирует либо одну, либо многозадачность ert_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 и matlabroot/ toolbox/rtw/targets/ecoder/example_file_process.tlc в рабочую папку, которая находится вне структуры папки MATLAB, но в пути MATLAB или TLC, переименуйте их (для примера добавьте префикс test_ к каждому файлу) и обновляйте панель 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()>.

Пользовательские лексемы не поддерживаются при генерации кода С++.