exponenta event banner

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

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

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

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

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

  • Генерация включает, определяет, в стандартные созданные файлы (например, 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 ®. Выберите активный набор конфигурации модели и откройте панель Создание кода (Code Generation) активного набора конфигурации.

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

  9. На вкладке Разное установите флажок Только генерировать код.

  10. Нажмите кнопку «Применить».

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

    Warning:  Overriding example ert_main.c!
    

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

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

    Обратите внимание, что список «Сгенерированный код» содержит следующие файлы:

    • В разделе «Основной файл» ert_main.c.

    • В разделе «Другие файлы» 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);
}

Добавление кода к стандартным файлам

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) диалогового окна Параметры конфигурации (Configuration Parameters). Шаблон CFP можно использовать для переопределения нормального поведения и создания основного программного модуля, настроенного для целевой среды.

Для поддержки формирования основных программных модулей предусмотрены два файла TLC:

  • bareboard_srmain.tlc: Код TLC для создания примера односкоростного основного программного модуля для целевой среды barebord. Код генерируется одной функцией TLC, FcnSingleTaskingMain.

  • bareboard_mrmain.tlc: Код TLC для создания многоскоростного основного программного модуля для целевой среды barebord. Код генерируется одной функцией 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 функция должна отменить выбор и отключить параметр Generate a example main program. Это предотвращает использование переменной TLC GenerateSampleERTMain от установлено до TLC_TRUE.

См. раздел Структура rtwgensettings для получения информации о создании SelectCallback функция.

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

slConfigUISetVal(hDlg, hSrc, 'GenerateSampleERTMain', 'off');
slConfigUISetEnabled(hDlg, hSrc, 'GenerateSampleERTMain',0);
hSrc.refreshDialog;

Примечание

Создание основной программы для целевой среды требует определенной настройки; например, в среде bareborand необходимо присоединить 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. 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()>.

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