pre-release 1.04
This commit is contained in:
@@ -1,37 +1,45 @@
|
||||
classdef periphConfig
|
||||
% Класс для управления конфигурацией периферии в маске Simulink
|
||||
% Динамически создает элементы маски на основе JSON конфигурации
|
||||
|
||||
methods(Static)
|
||||
function updateMask(blockPath, config)
|
||||
% blockPath = [blockPath '/MCU'];
|
||||
|
||||
% Проверяем, была ли маска открыта
|
||||
% wasOpen = isMaskDialogOpen(blockPath);
|
||||
% Основная функция обновления маски на основе конфигурации
|
||||
% Динамически создает вкладки и параметры для периферийных модулей
|
||||
% blockPath - путь к блоку Simulink
|
||||
% config - структура конфигурации из JSON файла
|
||||
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
|
||||
% Сохраняем состояние таблиц перед изменением маски
|
||||
tableNames = {'incTable', 'srcTable'};
|
||||
columns_backup = customtable.save_all_tables(tableNames);
|
||||
|
||||
try
|
||||
% Получаем настройки ширины строк из параметра маски
|
||||
rowWidth = str2double(get_param(blockPath, 'rowWidth'));
|
||||
|
||||
% Очищаем контейнер конфигурации перед созданием новых элементов
|
||||
containerName = 'configTabAll';
|
||||
periphConfig.clear_all_from_container(mask, containerName);
|
||||
|
||||
% Ищем контейнер, в который будем добавлять вкладки
|
||||
% Получаем контейнер для вкладок конфигурации
|
||||
container = mask.getDialogControl(containerName);
|
||||
if isempty(container)
|
||||
error('Контейнер "%s" не найден в маске.', containerName);
|
||||
end
|
||||
|
||||
% Обрабатываем конфигурацию если она не пустая
|
||||
if ~isempty(config)
|
||||
% Проходим по каждому модулю (ADC, TIM...)
|
||||
% Проходим по каждому модулю периферии (ADC, TIM, UART и т.д.)
|
||||
periphs = fieldnames(config);
|
||||
for i = 1:numel(periphs)
|
||||
periph = periphs{i};
|
||||
|
||||
% Сохраняем код, если он есть
|
||||
% Сохраняем код модуля (исходники и инклюды) в скрытые параметры
|
||||
periphConfig.store_single_periph_code(mask, periph, config.(periph));
|
||||
|
||||
% Проверяем наличие Defines
|
||||
% Пропускаем модули без секции Defines
|
||||
if ~isfield(config.(periph), 'Defines')
|
||||
continue;
|
||||
end
|
||||
@@ -39,68 +47,78 @@ classdef periphConfig
|
||||
defines = config.(periph).Defines;
|
||||
defNames = fieldnames(defines);
|
||||
|
||||
% Создаём вкладку для модуля
|
||||
% Создаем вкладку для модуля периферии
|
||||
tabCtrl = container.addDialogControl('tab', periph);
|
||||
tabCtrl.Prompt = [periph ' Config'];
|
||||
tabCtrl.Prompt = [periph ' Config']; % Отображаемое имя вкладки
|
||||
|
||||
% Карта для отслеживания количества строк в каждой вкладке
|
||||
rowCountMap = containers.Map();
|
||||
|
||||
% Добавляем все параметры Defines в созданную вкладку
|
||||
for j = 1:numel(defNames)
|
||||
defPrompt = defNames{j};
|
||||
def = defines.(defPrompt);
|
||||
|
||||
% Вызов функции добавления одного параметра
|
||||
% Добавление одного параметра конфигурации
|
||||
periphConfig.addConfig(mask, containerName, periph, defPrompt, def, rowCountMap, rowWidth);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% Создаем скрытые параметры для хранения кода периферии
|
||||
periphConfig.create_all_code_storage_params(blockPath, config);
|
||||
% periphConfig.cleanup_obsolete_code_params(blockPath, config);
|
||||
|
||||
|
||||
% Обновляем состояние маски (включение/выключение вкладок)
|
||||
periphConfig.update();
|
||||
|
||||
% Восстанавлиperiph = allTabNamesваем таблицы
|
||||
% Восстанавливаем таблицы после изменений
|
||||
customtable.restore_all_tables(tableNames, columns_backup);
|
||||
catch
|
||||
% Восстанавливаем таблицы
|
||||
% В случае ошибки восстанавливаем таблицы
|
||||
customtable.restore_all_tables(tableNames, columns_backup);
|
||||
end
|
||||
% % Повторно открываем маску, если она была открыта
|
||||
% if wasOpen
|
||||
% open_system(blockPath, 'mask');
|
||||
% end
|
||||
end
|
||||
|
||||
function update()
|
||||
% Обновление состояния маски - включение/выключение вкладок
|
||||
% на основе состояний чекбоксов управления
|
||||
|
||||
blockPath = gcb;
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
|
||||
% Читаем текущую конфигурацию
|
||||
config = configJs.read(blockPath);
|
||||
containerName = 'configTabAll';
|
||||
container = mask.getDialogControl(containerName);
|
||||
|
||||
% Получаем все параметры для проверки наличия чекбоксов
|
||||
paramsAll = mcuMask.collect_all_parameters(container);
|
||||
% Получаем все имена в кладок из container (у вас должен быть container)
|
||||
|
||||
% Получаем имена всех вкладок в контейнере
|
||||
allTabs = container.DialogControls;
|
||||
allTabNames = arrayfun(@(t) t.Name, allTabs, 'UniformOutput', false);
|
||||
|
||||
fieldsConfig = fieldnames(config);
|
||||
% Цикл по всем вкладкам в контейнере
|
||||
|
||||
% Обрабатываем каждую вкладку
|
||||
for i = 1:length(allTabNames)
|
||||
periph = fieldsConfig{i};
|
||||
|
||||
% Попытка найти параметр чекбокса Tab_<Periph>_Enable
|
||||
% Проверяем наличие чекбокса управления для этой вкладки
|
||||
checkboxName = ['Tab_' periph '_Enable'];
|
||||
if ismember(checkboxName, paramsAll)
|
||||
% Чекбокс есть - проверяем его состояние
|
||||
% Чекбокс найден - управляем состоянием вкладки
|
||||
paramObj = mask.getParameter(checkboxName);
|
||||
val = paramObj.Value;
|
||||
|
||||
try
|
||||
tab = container.getDialogControl(periph);
|
||||
if strcmpi(val, 'off')
|
||||
% Выключаем вкладку и очищаем связанные параметры
|
||||
tab.Enabled = 'off';
|
||||
% Рекурсивно очищаем связанные скрытые параметры
|
||||
periphConfig.clear_tab_params(mask, config.(periph), periph);
|
||||
else
|
||||
% Включаем вкладку и синхронизируем параметры
|
||||
tab.Enabled = 'on';
|
||||
periphConfig.sync_tab_params(mask, config.(periph), periph);
|
||||
end
|
||||
@@ -109,31 +127,32 @@ classdef periphConfig
|
||||
end
|
||||
|
||||
else
|
||||
% Чекбокса нет — просто пытаемся включить вкладку, если она есть
|
||||
% Чекбокса нет - просто включаем вкладку
|
||||
try
|
||||
tab = container.getDialogControl(periph);
|
||||
tab.Enabled = 'on';
|
||||
% Опционально можно синхронизировать параметры, если есть config поле
|
||||
% Синхронизируем параметры если есть конфигурация
|
||||
if isfield(config, periph)
|
||||
periphConfig.sync_tab_params(mask, config.(periph), periph);
|
||||
periphConfig.sync_tab_params(mask, config.(periph), periph);
|
||||
end
|
||||
catch
|
||||
% Можно не выводить предупреждение — вкладка может быть необязательной
|
||||
% warning('Вкладка с именем "%s" не найдена.', periph);
|
||||
% Вкладка может быть необязательной - игнорируем ошибку
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function periphParamCallback(paramName)
|
||||
% Callback-функция для параметров периферии
|
||||
% Обрабатывает изменения чекбоксов и других параметров
|
||||
|
||||
blockPath = gcb;
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
hObj = mask.getParameter(paramName);
|
||||
config = configJs.read(blockPath);
|
||||
container = mask.getDialogControl('configTabAll');
|
||||
|
||||
% === Проверка на Tab_<Periph>_Enable ===
|
||||
% === Обработка чекбоксов управления вкладками ===
|
||||
exprTab = '^Tab_(\w+)_Enable$';
|
||||
tokensTab = regexp(paramName, exprTab, 'tokens');
|
||||
|
||||
@@ -145,11 +164,13 @@ classdef periphConfig
|
||||
paramVal = hObj.Value;
|
||||
|
||||
if strcmpi(paramVal, 'off')
|
||||
% Выключаем вкладку и очищаем параметры
|
||||
tab.Enabled = 'off';
|
||||
if isfield(config, periph)
|
||||
periphConfig.clear_tab_params(mask, config.(periph), periph);
|
||||
end
|
||||
else
|
||||
% Включаем вкладку и синхронизируем параметры
|
||||
tab.Enabled = 'on';
|
||||
if isfield(config, periph)
|
||||
periphConfig.sync_tab_params(mask, config.(periph), periph);
|
||||
@@ -161,19 +182,17 @@ classdef periphConfig
|
||||
return;
|
||||
end
|
||||
|
||||
% === Проверка на параметр, связанный с Sources/Includes ===
|
||||
% Проверка: это параметр, у которого есть соответствующий Hidden_<Name>_Sources или Hidden_<Name>_Includes
|
||||
% === Обработка параметров, связанных с Sources/Includes ===
|
||||
nameBase = paramName;
|
||||
|
||||
paramNames = string({mask.Parameters.Name});
|
||||
hasSources = any(paramNames == "Hidden_" + nameBase + "_Sources");
|
||||
hasIncludes = any(paramNames == "Hidden_" + nameBase + "_Includes");
|
||||
|
||||
|
||||
if hasSources || hasIncludes
|
||||
useVal = hObj.Value;
|
||||
|
||||
% Получаем содержимое config по nameBase — возможно, вложенное
|
||||
% Получаем структуру конфигурации для этого параметра
|
||||
try
|
||||
valueStruct = configJs.get_field(config, nameBase);
|
||||
catch
|
||||
@@ -182,49 +201,50 @@ classdef periphConfig
|
||||
end
|
||||
|
||||
if strcmpi(useVal, 'on')
|
||||
% Сохраняем код если параметр включен
|
||||
try
|
||||
periphConfig.store_single_periph_code(mask, nameBase, valueStruct);
|
||||
catch
|
||||
warning('Не удалось сохранить параметры для %s.', nameBase);
|
||||
end
|
||||
else
|
||||
% Очищаем код если параметр выключен
|
||||
periphConfig.clear_single_periph_code_param(mask, nameBase);
|
||||
end
|
||||
|
||||
return;
|
||||
end
|
||||
|
||||
|
||||
% === Если не подошло ни под одно из условий ===
|
||||
% warning('Объект "%s" не поддерживается универсальным коллбеком.', paramName);
|
||||
end
|
||||
|
||||
function updatePeriphRunMexBat()
|
||||
% Запись run_mex.bat
|
||||
% Обновление BAT-файла для компиляции с кодом периферии
|
||||
% Собирает все исходники и инклюды из скрытых параметров
|
||||
|
||||
blockPath = gcb;
|
||||
% Восстанавливаем код периферии из скрытых параметров маски
|
||||
CodeStruct = periphConfig.restore_periph_code_from_mask(blockPath);
|
||||
periphPath = mcuPath.get('periphPath');
|
||||
[periphPath, ~, ~] = fileparts(periphPath);
|
||||
|
||||
% Добавляем код в BAT-файл компиляции
|
||||
periphConfig.addCodeBat(CodeStruct, periphPath);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
methods(Static, Access=private)
|
||||
|
||||
|
||||
|
||||
function addHiddenParam(mask, containerName, nameBase, kind, existingParams)
|
||||
% Преобразуем к красивому имени
|
||||
% Создание скрытого параметра для хранения кода
|
||||
% nameBase - базовое имя параметра
|
||||
% kind - тип ('Sources' или 'Includes')
|
||||
|
||||
prettyName = strrep(nameBase, '_', ' ');
|
||||
paramName = ['Hidden_' char(nameBase) '_' kind];
|
||||
|
||||
% Проверяем не существует ли уже параметр
|
||||
if ismember(paramName, existingParams)
|
||||
return;
|
||||
end
|
||||
|
||||
% Создаем скрытый параметр
|
||||
mask.addParameter( ...
|
||||
'Name', paramName, ...
|
||||
'Type', 'edit', ...
|
||||
@@ -233,14 +253,16 @@ classdef periphConfig
|
||||
'Visible', 'off', ...
|
||||
'Container', containerName ...
|
||||
);
|
||||
fprintf('Создан скрытый параметр: %s\n', paramName);
|
||||
end
|
||||
|
||||
function clear_tab_params(mask, configStruct, prefix, depth)
|
||||
% Рекурсивная очистка параметров вкладки
|
||||
% Используется при выключении вкладки
|
||||
|
||||
if nargin < 4
|
||||
depth = 0;
|
||||
end
|
||||
maxDepth = 3; % Максимальная глубина рекурсии
|
||||
maxDepth = 3; % Ограничение глубины рекурсии
|
||||
|
||||
fields = fieldnames(configStruct);
|
||||
|
||||
@@ -251,10 +273,11 @@ classdef periphConfig
|
||||
|
||||
if isstruct(value)
|
||||
if depth < maxDepth
|
||||
% Рекурсивный вызов для вложенных структур с увеличением глубины
|
||||
% Рекурсивный вызов для вложенных структур
|
||||
periphConfig.clear_tab_params(mask, value, paramName, depth + 1);
|
||||
end
|
||||
else
|
||||
% Очищаем параметры Sources/Includes
|
||||
if strcmp(key, 'Sources') || strcmp(key, 'Includes')
|
||||
baseName = configJs.get_final_name_from_prefix(prefix);
|
||||
periphConfig.clear_single_periph_code_param(mask, baseName);
|
||||
@@ -263,12 +286,14 @@ classdef periphConfig
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function sync_tab_params(mask, configStruct, prefix, depth)
|
||||
% Рекурсивная синхронизация параметров вкладки
|
||||
% Используется при включении вкладки
|
||||
|
||||
if nargin < 4
|
||||
depth = 0;
|
||||
end
|
||||
maxDepth = 3; % Максимальная глубина рекурсии
|
||||
maxDepth = 3;
|
||||
|
||||
fields = fieldnames(configStruct);
|
||||
|
||||
@@ -279,7 +304,6 @@ classdef periphConfig
|
||||
|
||||
if isstruct(value)
|
||||
if depth < maxDepth
|
||||
% Рекурсивный вызов для вложенных структур с увеличением глубины
|
||||
periphConfig.sync_tab_params(mask, value, paramName, depth + 1);
|
||||
end
|
||||
else
|
||||
@@ -292,13 +316,15 @@ classdef periphConfig
|
||||
end
|
||||
|
||||
function create_all_code_storage_params(blockPath, config)
|
||||
% Создание всех скрытых параметров для хранения кода периферии
|
||||
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
|
||||
containerName = 'configTabAll';
|
||||
container = mask.getDialogControl(containerName);
|
||||
existingParams = mcuMask.collect_all_parameters(container);
|
||||
|
||||
% Убедимся, что контейнер существует
|
||||
% Создаем скрытую вкладку для хранения параметров кода
|
||||
tabName = 'hiddenCodeTab';
|
||||
tab = mask.getDialogControl(tabName);
|
||||
if isempty(tab)
|
||||
@@ -309,20 +335,22 @@ classdef periphConfig
|
||||
tab.Visible = 'off';
|
||||
end
|
||||
|
||||
% Запуск рекурсивного обхода
|
||||
% Рекурсивный обход конфигурации для создания параметров
|
||||
periphConfig.process_struct_recursive(mask, tabName, config, {}, existingParams);
|
||||
end
|
||||
|
||||
function process_struct_recursive(mask, tabName, currentStruct, nameStack, existingParams)
|
||||
% Рекурсивный обход структуры конфигурации
|
||||
% Создает скрытые параметры для всех Sources и Includes
|
||||
|
||||
fields = fieldnames(currentStruct);
|
||||
for i = 1:numel(fields)
|
||||
fieldName = fields{i};
|
||||
value = currentStruct.(fieldName);
|
||||
newStack = [nameStack, fieldName]; % Добавляем уровень к имени
|
||||
newStack = [nameStack, fieldName];
|
||||
|
||||
% Если value — структура, обходим дальше
|
||||
if isstruct(value)
|
||||
% Проверяем: это структура с Sources/Includes или просто промежуточный узел?
|
||||
% Проверяем наличие Sources и Includes в структуре
|
||||
hasSources = isfield(value, 'Sources');
|
||||
hasIncludes = isfield(value, 'Includes');
|
||||
|
||||
@@ -339,33 +367,37 @@ classdef periphConfig
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function cleanup_obsolete_code_params(blockPath, config)
|
||||
% Очистка устаревших скрытых параметров
|
||||
% Удаляет параметры для периферии, которой больше нет в конфигурации
|
||||
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
maskParams = mask.Parameters;
|
||||
|
||||
% Получаем список актуальных периферий
|
||||
% Получаем список актуальных периферийных модулей
|
||||
validPeriphs = fieldnames(config);
|
||||
|
||||
for i = 1:numel(maskParams)
|
||||
paramName = maskParams(i).Name;
|
||||
|
||||
% Проверяем, является ли параметром хранения Sources или Includes
|
||||
% Ищем параметры хранения кода
|
||||
expr = '^Hidden_(\w+)_(Sources|Includes)$';
|
||||
tokens = regexp(paramName, expr, 'tokens');
|
||||
if ~isempty(tokens)
|
||||
periph = tokens{1}{1};
|
||||
|
||||
% Если периферии больше нет – удаляем параметр
|
||||
% Удаляем параметр если периферия больше не существует
|
||||
if ~ismember(periph, validPeriphs)
|
||||
mask.removeParameter(paramName);
|
||||
fprintf('Удалён устаревший параметр: %s\n', paramName);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function codeStruct = restore_periph_code_from_mask(blockPath)
|
||||
% Восстановление кода периферии из скрытых параметров маски
|
||||
% Собирает все Sources и Includes в одну структуру
|
||||
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
maskParams = mask.Parameters;
|
||||
|
||||
@@ -375,26 +407,27 @@ classdef periphConfig
|
||||
for i = 1:numel(maskParams)
|
||||
name = maskParams(i).Name;
|
||||
|
||||
% Ищем параметры Sources
|
||||
% Поиск параметров Sources
|
||||
tokensSrc = regexp(name, '^Hidden_(\w+)_Sources$', 'tokens');
|
||||
if ~isempty(tokensSrc)
|
||||
val = maskParams(i).Value;
|
||||
|
||||
if ischar(val) || isstring(val)
|
||||
valStr = strtrim(char(val));
|
||||
% Пропускаем пустые строки и '[]'
|
||||
% Пропускаем пустые значения
|
||||
if isempty(valStr) || strcmp(valStr, '[]')
|
||||
continue;
|
||||
end
|
||||
|
||||
% Разбиваем на строки и фильтруем пустые
|
||||
lines = splitlines(valStr);
|
||||
lines = lines(~cellfun(@(x) all(isspace(x)) || isempty(x), lines));
|
||||
allSources = [allSources; lines]; %#ok<AGROW>
|
||||
allSources = [allSources; lines];
|
||||
end
|
||||
continue;
|
||||
end
|
||||
|
||||
% Ищем параметры Includes
|
||||
% Поиск параметров Includes
|
||||
tokensInc = regexp(name, '^Hidden_(\w+)_Includes$', 'tokens');
|
||||
if ~isempty(tokensInc)
|
||||
val = maskParams(i).Value;
|
||||
@@ -407,27 +440,28 @@ classdef periphConfig
|
||||
|
||||
lines = splitlines(valStr);
|
||||
lines = lines(~cellfun(@(x) all(isspace(x)) || isempty(x), lines));
|
||||
allIncludes = [allIncludes; lines]; %#ok<AGROW>
|
||||
allIncludes = [allIncludes; lines];
|
||||
end
|
||||
continue;
|
||||
end
|
||||
end
|
||||
|
||||
% Формируем результирующую структуру
|
||||
codeStruct = struct();
|
||||
codeStruct.Sources = allSources;
|
||||
codeStruct.Includes = allIncludes;
|
||||
end
|
||||
|
||||
|
||||
function clear_all_from_container(mask, containerName)
|
||||
% allControls = mask.getDialogControls();
|
||||
% Полная очистка контейнера - удаление всех параметров и вкладок
|
||||
|
||||
container = mask.getDialogControl(containerName);
|
||||
if isempty(container)
|
||||
warning('Контейнер "%s" не найден.', containerName);
|
||||
return;
|
||||
end
|
||||
|
||||
% Рекурсивно собрать все параметры (не вкладки)
|
||||
% Собираем все параметры в контейнере
|
||||
paramsToDelete = mcuMask.collect_all_parameters(container);
|
||||
|
||||
% Удаляем все параметры
|
||||
@@ -439,30 +473,27 @@ classdef periphConfig
|
||||
end
|
||||
end
|
||||
|
||||
% Рекурсивно удалить все вкладки внутри контейнера
|
||||
% Рекурсивно удаляем все вкладки
|
||||
mcuMask.delete_all_tabs(mask, container);
|
||||
end
|
||||
|
||||
|
||||
function res = addCodeBat(codeConfig, codePath)
|
||||
% Добавить сурсы и пути в батник
|
||||
% Возвращает 0 при успехе, 1 при ошибке
|
||||
% Добавление кода периферии в BAT-файл компиляции
|
||||
|
||||
try
|
||||
% Формируем строки
|
||||
% Формируем строки для BAT-файла
|
||||
srcText = compiler.createSourcesBat('code_PERIPH', codeConfig.Sources, codePath);
|
||||
incText = compiler.createIncludesBat('includes_PERIPH', codeConfig.Includes, codePath);
|
||||
|
||||
% Записываем результат
|
||||
res = compiler.updateRunMexBat(srcText, incText, ':: PERIPH BAT'); % Всё прошло успешно
|
||||
% Обновляем BAT-файл
|
||||
res = compiler.updateRunMexBat(srcText, incText, ':: PERIPH BAT');
|
||||
catch
|
||||
% В случае ошибки просто возвращаем 1
|
||||
res = 1;
|
||||
res = 1; % Ошибка
|
||||
end
|
||||
end
|
||||
|
||||
function res = addUserFunctions(userCodeConfig)
|
||||
% Добавить функции и дефайны в исходный код wrapper
|
||||
% userCodeConfig — структура config.UserCode
|
||||
% Добавление пользовательских функций в код обёртки
|
||||
|
||||
initFuncsText = '';
|
||||
simFuncsText = '';
|
||||
@@ -471,43 +502,45 @@ classdef periphConfig
|
||||
if isfield(userCodeConfig, 'Functions')
|
||||
funcs = userCodeConfig.Functions;
|
||||
|
||||
% Обрабатываем функции инициализации
|
||||
if isfield(funcs, 'PeriphInit')
|
||||
initFuncs = funcs.PeriphInit;
|
||||
initFuncsText = strjoin(strcat('\t', initFuncs, ';'), '\n');
|
||||
end
|
||||
|
||||
% Обрабатываем функции симуляции
|
||||
if isfield(funcs, 'PeriphSimulation')
|
||||
simFuncs = funcs.PeriphSimulation;
|
||||
simFuncsText = strjoin(strcat('\t', simFuncs, ';'), '\n');
|
||||
end
|
||||
|
||||
% Обрабатываем функции деинициализации
|
||||
if isfield(funcs, 'PeriphDeinit')
|
||||
deinitFuncs = funcs.PeriphDeinit;
|
||||
deinitFuncsText = strjoin(strcat('\t', deinitFuncs, ';'), '\n');
|
||||
end
|
||||
|
||||
% Записываем функции в файл обёртки
|
||||
res = periphConfig.writeWrapperCode(initFuncsText, simFuncsText, deinitFuncsText);
|
||||
end
|
||||
end
|
||||
|
||||
function res = writeWrapperCode(initFuncsText, simFuncsText, deinitFuncsText)
|
||||
% Входные параметры:
|
||||
% srcText - текст для записи set code_...
|
||||
% incText - текст для записи set includes_...
|
||||
%
|
||||
% Возвращает:
|
||||
% res - 0 при успехе, 1 при ошибке
|
||||
% Запись пользовательских функций в файл mcu_wrapper.c
|
||||
|
||||
wrapPath = fullfile(mcuPath.get('wrapperPath'), 'mcu_wrapper.c');
|
||||
res = 1;
|
||||
try
|
||||
% Читаем текущее содержимое файла
|
||||
code = fileread(wrapPath);
|
||||
code = regexprep(code, '\r\n?', '\n');
|
||||
|
||||
% Записываем строки initFuncsText и simFuncsText
|
||||
% Вставляем функции в соответствующие секции
|
||||
code = editCode.insertSection(code, '// PERIPH INIT', initFuncsText);
|
||||
code = editCode.insertSection(code, '// PERIPH SIM', simFuncsText);
|
||||
code = editCode.insertSection(code, '// PERIPH DEINIT', deinitFuncsText);
|
||||
|
||||
% Записываем обновленный файл
|
||||
fid = fopen(wrapPath, 'w', 'n', 'UTF-8');
|
||||
if fid == -1
|
||||
error('Не удалось открыть файл для записи');
|
||||
@@ -521,18 +554,22 @@ classdef periphConfig
|
||||
end
|
||||
|
||||
function addConfig(mask, containerName, periphName, defPrompt, def, rowCountMap, rowWidth)
|
||||
% mask — объект маски Simulink.Mask.get(blockPath)
|
||||
% containerName — имя контейнера, в который добавляем параметр (например, 'configTabAll')
|
||||
% periphName — имя вкладки / контейнера для текущего периферийного блока (например, 'ADC')
|
||||
% defPrompt — имя параметра в Defines (например, 'shift_enable')
|
||||
% def — структура с описанием параметра (Prompt, Def, Type, Default, NewRow и т.п.)
|
||||
|
||||
% Добавление одного параметра конфигурации в маску
|
||||
% mask - объект маски
|
||||
% containerName - имя контейнера
|
||||
% periphName - имя периферийного модуля
|
||||
% defPrompt - имя параметра
|
||||
% def - структура с описанием параметра
|
||||
% rowCountMap - карта для отслеживания строк
|
||||
% rowWidth - ширина строки
|
||||
|
||||
% Инициализация счетчика строк для этого модуля
|
||||
if ~isKey(rowCountMap, periphName)
|
||||
rowCountMap(periphName) = 0;
|
||||
end
|
||||
rowCount = rowCountMap(periphName) + 1;
|
||||
|
||||
% Устанавливаем NewRow, если он не задан
|
||||
% Определяем начинать ли новую строку
|
||||
if ~isfield(def, 'NewRow')
|
||||
def.NewRow = mod(rowCount - 1, rowWidth) == 0;
|
||||
elseif def.NewRow == true
|
||||
@@ -540,20 +577,20 @@ classdef periphConfig
|
||||
end
|
||||
rowCountMap(periphName) = rowCount;
|
||||
|
||||
% Найдем контейнер с таким именем
|
||||
% Получаем контейнер
|
||||
container = mask.getDialogControl(containerName);
|
||||
if isempty(container)
|
||||
error('Контейнер "%s" не найден в маске.', containerName);
|
||||
end
|
||||
|
||||
% Проверим, есть ли вкладка с именем periphName, если нет — создадим
|
||||
% Создаем вкладку если её нет
|
||||
tabCtrl = mask.getDialogControl(periphName);
|
||||
if isempty(tabCtrl)
|
||||
tabCtrl = container.addDialogControl('tab', periphName);
|
||||
tabCtrl.Prompt = [periphName ' Config'];
|
||||
end
|
||||
|
||||
% Определяем тип параметра (checkbox или edit)
|
||||
% Определяем тип параметра
|
||||
switch lower(def.Type)
|
||||
case 'checkbox'
|
||||
paramType = 'checkbox';
|
||||
@@ -562,20 +599,20 @@ classdef periphConfig
|
||||
case 'popup'
|
||||
paramType = 'popup';
|
||||
otherwise
|
||||
% Игнорируем остальные типы
|
||||
return;
|
||||
return; % Пропускаем неизвестные типы
|
||||
end
|
||||
|
||||
% Создаем валидное имя параметра
|
||||
paramName = matlab.lang.makeValidName(defPrompt);
|
||||
|
||||
% Получаем значение
|
||||
% Устанавливаем значение по умолчанию
|
||||
if strcmp(paramType, 'popup')
|
||||
if isfield(def, 'Def') && iscell(def.Def) && ~isempty(def.Def)
|
||||
choices = def.Def;
|
||||
valStr = ''; % по умолчанию — ничего
|
||||
valStr = '';
|
||||
elseif isfield(def, 'Options')
|
||||
choices = def.Def;
|
||||
valStr = ''; % по умолчанию — ничего
|
||||
valStr = '';
|
||||
else
|
||||
warning('Popout параметр "%s" не содержит допустимого списка в Def.', defPrompt);
|
||||
return;
|
||||
@@ -636,12 +673,11 @@ classdef periphConfig
|
||||
param.Callback = callback;
|
||||
end
|
||||
|
||||
|
||||
|
||||
%% ELEMENTARY
|
||||
%% ELEMENTARY FUNCTIONS - базовые вспомогательные функции
|
||||
|
||||
function clear_single_periph_code_param(mask, periph)
|
||||
% Очистка кода одного поля конфига
|
||||
% Очистка кода одного модуля периферии
|
||||
|
||||
paramNames = {
|
||||
['Hidden_' char(periph) '_Sources'],
|
||||
['Hidden_' char(periph) '_Includes']
|
||||
@@ -653,14 +689,14 @@ classdef periphConfig
|
||||
param = mask.getParameter(paramName);
|
||||
param.Value = '';
|
||||
catch
|
||||
% Параметр не существует — ничего не делаем
|
||||
% Параметр не существует - игнорируем
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function store_single_periph_code(mask, periph, code)
|
||||
% Запись кода одного поля конфига
|
||||
% Сохраняем Sources, если они есть
|
||||
% Сохранение кода одного модуля периферии в скрытые параметры
|
||||
|
||||
if isfield(code, 'Sources')
|
||||
paramName = ['Hidden_' char(periph) '_Sources'];
|
||||
try
|
||||
@@ -671,7 +707,6 @@ classdef periphConfig
|
||||
end
|
||||
end
|
||||
|
||||
% Сохраняем Includes, если они есть
|
||||
if isfield(code, 'Includes')
|
||||
paramName = ['Hidden_' char(periph) '_Includes'];
|
||||
try
|
||||
@@ -683,15 +718,13 @@ classdef periphConfig
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function res = ternary(cond, valTrue, valFalse)
|
||||
% Вспомогательная функция - тернарный оператор
|
||||
if cond
|
||||
res = valTrue;
|
||||
else
|
||||
res = valFalse;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user