добавлена поддержка popup в конфиге
добавлена задание src в run_bat.mex по чекбоксу исправлены лишние абзацы в disp
This commit is contained in:
parent
058d3a00cf
commit
7c2fb99908
@ -26,10 +26,11 @@ classdef compiler
|
||||
% Список заголовочных файлов (.h)
|
||||
includes = { '.\'
|
||||
};
|
||||
periphPath = mcuPath.get('wrapperPath');
|
||||
wrapperPath = mcuPath.get('wrapperPath');
|
||||
% [wrapperPath, ~, ~] = fileparts(wrapperPath);
|
||||
% Формируем строки
|
||||
wrapperSrcText = compiler.createSourcesBat('code_WRAPPER', sources, periphPath);
|
||||
wrapperIncText = compiler.createIncludesBat('includes_WRAPPER', includes, periphPath);
|
||||
wrapperSrcText = compiler.createSourcesBat('code_WRAPPER', sources, wrapperPath);
|
||||
wrapperIncText = compiler.createIncludesBat('includes_WRAPPER', includes, wrapperPath);
|
||||
|
||||
% Записываем результат
|
||||
res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: WRAPPER BAT'); % Всё прошло успешно
|
||||
|
@ -300,9 +300,13 @@ classdef mcuMask
|
||||
out = sprintf(varargin{:});
|
||||
end
|
||||
|
||||
out_now = get_param(gcb, 'consoleOutput');
|
||||
out_now = get_param(gcb, 'consoleOutput');
|
||||
if ~strcmp(out, '') && ~strcmp(out_now, '')
|
||||
set_param(gcb, 'consoleOutput', [out_now newline out]);
|
||||
else
|
||||
set_param(gcb, 'consoleOutput', [out_now out]);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function updateModelAsync()
|
||||
|
@ -69,7 +69,7 @@ function res = mexing(compile_mode)
|
||||
config = periphConfig.read_config(blockPath);
|
||||
config = periphConfig.update_config(blockPath, config);
|
||||
periphConfig.write_config(config);
|
||||
periphConfig.update(blockPath, config);
|
||||
periphConfig.updateMask(blockPath, config);
|
||||
end
|
||||
end
|
||||
|
||||
@ -202,6 +202,8 @@ function definesWrapperArg = buildConfigDefinesString()
|
||||
definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0);
|
||||
case 'edit'
|
||||
definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1);
|
||||
case 'popup'
|
||||
definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0);
|
||||
otherwise
|
||||
% Необрабатываемые типы
|
||||
end
|
||||
@ -230,7 +232,15 @@ function definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, val_
|
||||
end
|
||||
|
||||
% Берём alias из маски
|
||||
alias = param.Alias;
|
||||
if ~strcmp(param.Type, 'popup')
|
||||
def_name = param.Alias;
|
||||
else
|
||||
def_name = param.Value;
|
||||
end
|
||||
|
||||
if strcmp(def_name, '')
|
||||
return;
|
||||
end
|
||||
|
||||
if val_define ~= 0
|
||||
% Значение параметра
|
||||
@ -240,14 +250,16 @@ function definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, val_
|
||||
val = num2str(val); % Преобразуем результат в строку
|
||||
end
|
||||
% Формируем define с кавычками и значением
|
||||
newDefine = ['-D"' alias '__EQ__' val '"'];
|
||||
else
|
||||
newDefine = ['-D"' def_name '__EQ__' val '"'];
|
||||
elseif ~strcmp(param.Type, 'popup')
|
||||
if mcuMask.read_checkbox(paramName)
|
||||
% Формируем define с кавычками без значения
|
||||
newDefine = ['-D"' alias '"'];
|
||||
newDefine = ['-D"' def_name '"'];
|
||||
else
|
||||
newDefine = '';
|
||||
end
|
||||
else
|
||||
newDefine = ['-D"' def_name '"'];
|
||||
end
|
||||
|
||||
|
||||
|
@ -1,76 +1,65 @@
|
||||
classdef periphConfig
|
||||
|
||||
methods(Static)
|
||||
function update(blockPath, config)
|
||||
function updateMask(blockPath, config)
|
||||
% blockPath = [blockPath '/MCU'];
|
||||
|
||||
% Проверяем, была ли маска открыта
|
||||
% wasOpen = isMaskDialogOpen(blockPath);
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
periphPath = mcuPath.get('periphPath');
|
||||
[periphPath, ~, ~] = fileparts(periphPath);
|
||||
|
||||
tableNames = {'incTable', 'srcTable'};
|
||||
columns_backup = customtable.save_all_tables(tableNames);
|
||||
|
||||
containerName = 'configTabAll';
|
||||
periphConfig.clear_all_from_container(mask, containerName);
|
||||
|
||||
% Ищем контейнер, в который будем добавлять вкладки
|
||||
container = mask.getDialogControl(containerName);
|
||||
if isempty(container)
|
||||
error('Контейнер "%s" не найден в маске.', containerName);
|
||||
end
|
||||
|
||||
if ~isempty(config)
|
||||
if isfield(config, 'Code')
|
||||
res = periphConfig.addCodeConfig(config.Code, periphPath);
|
||||
if res == 0
|
||||
error('Ошибка: неудачное добавление кода периферии. Проверьте корректность файлов и путей в конфигурационном файле')
|
||||
end
|
||||
else
|
||||
error('Ошибка: в конфигурационном файле не задан исходный код для симуляции периферии')
|
||||
try
|
||||
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...)
|
||||
periphs = fieldnames(config);
|
||||
for i = 1:numel(periphs)
|
||||
periph = periphs{i};
|
||||
|
||||
% Сохраняем код, если он есть
|
||||
periphConfig.store_single_periph_code(mask, periph, config.(periph));
|
||||
|
||||
% Проверяем наличие Defines
|
||||
if ~isfield(config.(periph), 'Defines')
|
||||
continue;
|
||||
end
|
||||
|
||||
defines = config.(periph).Defines;
|
||||
defNames = fieldnames(defines);
|
||||
|
||||
if isfield(config, 'UserCode')
|
||||
res = periphConfig.addUserCodeConfig(config.UserCode);
|
||||
if res == 0
|
||||
error('Ошибка: неудачное добавление функций для симуляции. Проверьте корректность названий функций в конфигурационном файле')
|
||||
end
|
||||
else
|
||||
error('Ошибка: в конфигурационном файле не заданы функции для симуляции периферии')
|
||||
end
|
||||
|
||||
% Проходим по каждому модулю (ADC, TIM...)
|
||||
periphs = fieldnames(config);
|
||||
for i = 1:numel(periphs)
|
||||
periph = periphs{i};
|
||||
|
||||
% Пропускаем Code и UserCode, они уже обработаны
|
||||
if strcmp(periph, 'Code') || strcmp(periph, 'UserCode')
|
||||
continue;
|
||||
end
|
||||
|
||||
|
||||
defines = config.(periph).Defines;
|
||||
defNames = fieldnames(defines);
|
||||
|
||||
% Создаём вкладку для модуля
|
||||
tabCtrl = container.addDialogControl('tab', periph);
|
||||
tabCtrl.Prompt = [periph ' Config'];
|
||||
|
||||
for j = 1:numel(defNames)
|
||||
defPrompt = defNames{j};
|
||||
def = defines.(defPrompt);
|
||||
|
||||
% Вызов функции добавления одного параметра
|
||||
periphConfig.addConfig(mask, containerName, periph, defPrompt, def);
|
||||
% Создаём вкладку для модуля
|
||||
tabCtrl = container.addDialogControl('tab', periph);
|
||||
tabCtrl.Prompt = [periph ' Config'];
|
||||
|
||||
for j = 1:numel(defNames)
|
||||
defPrompt = defNames{j};
|
||||
def = defines.(defPrompt);
|
||||
|
||||
% Вызов функции добавления одного параметра
|
||||
periphConfig.addConfig(mask, containerName, periph, defPrompt, def);
|
||||
end
|
||||
end
|
||||
end
|
||||
periphConfig.create_all_code_storage_params(blockPath, config);
|
||||
periphConfig.cleanup_obsolete_code_params(blockPath, config);
|
||||
|
||||
% Восстанавливаем таблицы
|
||||
customtable.restore_all_tables(tableNames, columns_backup);
|
||||
catch
|
||||
% Восстанавливаем таблицы
|
||||
customtable.restore_all_tables(tableNames, columns_backup);
|
||||
end
|
||||
% Восстанавливаем таблицы
|
||||
customtable.restore_all_tables(tableNames, columns_backup);
|
||||
|
||||
% % Повторно открываем маску, если она была открыта
|
||||
% if wasOpen
|
||||
% open_system(blockPath, 'mask');
|
||||
@ -169,9 +158,20 @@ classdef periphConfig
|
||||
function update_callback()
|
||||
blockPath = gcb;
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
|
||||
config = periphConfig.read_config(blockPath);
|
||||
|
||||
periphs = fieldnames(config);
|
||||
for i = 1:numel(periphs)
|
||||
periph = periphs{i};
|
||||
|
||||
% Сохраняем код, если он есть
|
||||
periphConfig.store_single_periph_code(mask, periph, config.(periph));
|
||||
end
|
||||
|
||||
containerName = 'configTabAll';
|
||||
container = mask.getDialogControl(containerName);
|
||||
paramsAll = mcuMask.collect_all_parameters(container);
|
||||
paramsAll = mcuMask.collect_all_parameters(container);
|
||||
% Цикл по параметрам
|
||||
for i = 1:length(paramsAll)
|
||||
name = paramsAll{i};
|
||||
@ -190,6 +190,7 @@ classdef periphConfig
|
||||
try
|
||||
tab = container.getDialogControl(periph);
|
||||
tab.Enabled = 'off';
|
||||
periphConfig.clear_single_periph_code_param(mask, periph);
|
||||
catch
|
||||
warning('Вкладка с именем "%s" не найдена.', periph);
|
||||
end
|
||||
@ -198,6 +199,7 @@ classdef periphConfig
|
||||
try
|
||||
tab = container.getDialogControl(periph);
|
||||
tab.Enabled = 'on';
|
||||
periphConfig.store_single_periph_code(mask, periph, config.(periph));
|
||||
catch
|
||||
warning('Вкладка с именем "%s" не найдена.', periph);
|
||||
end
|
||||
@ -205,20 +207,221 @@ classdef periphConfig
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
periphConfig.getWrapperCode();
|
||||
end
|
||||
|
||||
|
||||
|
||||
function getWrapperCode()
|
||||
blockPath = gcb;
|
||||
CodeStruct = periphConfig.restore_periph_code_from_mask(blockPath);
|
||||
periphPath = mcuPath.get('periphPath');
|
||||
[periphPath, ~, ~] = fileparts(periphPath);
|
||||
|
||||
periphConfig.addCodeBat(CodeStruct, periphPath);
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
methods(Static, Access=private)
|
||||
|
||||
function res = addCodeConfig(codeConfig, periphPath)
|
||||
function create_all_code_storage_params(blockPath, config)
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
existingParams = arrayfun(@(p) p.Name, mask.Parameters, 'UniformOutput', false);
|
||||
|
||||
periphs = fieldnames(config);
|
||||
for i = 1:numel(periphs)
|
||||
periph = periphs{i};
|
||||
|
||||
% Проверяем, нужно ли создавать параметры
|
||||
hasSources = isfield(config.(periph), 'Sources');
|
||||
hasIncludes = isfield(config.(periph), 'Includes');
|
||||
|
||||
if ~hasSources && ~hasIncludes
|
||||
continue;
|
||||
end
|
||||
|
||||
% Добавляем параметр для Sources
|
||||
if hasSources
|
||||
srcParamName = ['Hidden_' periph '_Sources'];
|
||||
if ~ismember(srcParamName, existingParams)
|
||||
mask.addParameter( ...
|
||||
'Name', srcParamName, ...
|
||||
'Type', 'edit', ...
|
||||
'Prompt', '', ...
|
||||
'Value', '', ...
|
||||
'Visible', 'off' ...
|
||||
);
|
||||
fprintf('Создан скрытый параметр: %s\n', srcParamName);
|
||||
end
|
||||
end
|
||||
|
||||
% Добавляем параметр для Includes
|
||||
if hasIncludes
|
||||
incParamName = ['Hidden_' periph '_Includes'];
|
||||
if ~ismember(incParamName, existingParams)
|
||||
mask.addParameter( ...
|
||||
'Name', incParamName, ...
|
||||
'Type', 'edit', ...
|
||||
'Prompt', '', ...
|
||||
'Value', '', ...
|
||||
'Visible', 'off' ...
|
||||
);
|
||||
fprintf('Создан скрытый параметр: %s\n', incParamName);
|
||||
end
|
||||
end
|
||||
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)
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
maskParams = mask.Parameters;
|
||||
|
||||
allSources = {};
|
||||
allIncludes = {};
|
||||
|
||||
for i = 1:numel(maskParams)
|
||||
name = maskParams(i).Name;
|
||||
|
||||
% Ищем параметры 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>
|
||||
end
|
||||
continue;
|
||||
end
|
||||
|
||||
% Ищем параметры Includes
|
||||
tokensInc = regexp(name, '^Hidden_(\w+)_Includes$', 'tokens');
|
||||
if ~isempty(tokensInc)
|
||||
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));
|
||||
allIncludes = [allIncludes; lines]; %#ok<AGROW>
|
||||
end
|
||||
continue;
|
||||
end
|
||||
end
|
||||
|
||||
codeStruct = struct();
|
||||
codeStruct.Sources = allSources;
|
||||
codeStruct.Includes = allIncludes;
|
||||
end
|
||||
|
||||
|
||||
|
||||
function clear_single_periph_code_param(mask, periph)
|
||||
% Формируем имена параметров
|
||||
paramNames = {
|
||||
['Hidden_' periph '_Sources'],
|
||||
['Hidden_' periph '_Includes']
|
||||
};
|
||||
|
||||
for i = 1:numel(paramNames)
|
||||
paramName = paramNames{i};
|
||||
try
|
||||
param = mask.getParameter(paramName);
|
||||
param.Value = '';
|
||||
catch
|
||||
% Параметр не существует — ничего не делаем
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function store_single_periph_code(mask, periph, code)
|
||||
% Сохраняем Sources, если они есть
|
||||
if isfield(code, 'Sources') && isfield(code.Sources, 'Options')
|
||||
paramName = ['Hidden_' periph '_Sources'];
|
||||
try
|
||||
param = mask.getParameter(paramName);
|
||||
param.Value = periphConfig.convert_code_value(code.Sources.Options);
|
||||
catch
|
||||
mcuMask.disp(0, ['Параметр ' paramName ' не найден']);
|
||||
end
|
||||
end
|
||||
|
||||
% Сохраняем Includes, если они есть
|
||||
if isfield(code, 'Includes') && isfield(code.Includes, 'Options')
|
||||
paramName = ['Hidden_' periph '_Includes'];
|
||||
try
|
||||
param = mask.getParameter(paramName);
|
||||
param.Value = periphConfig.convert_code_value(code.Includes.Options);
|
||||
catch
|
||||
mcuMask.disp(0, ['Параметр ' paramName ' не найден']);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function value = convert_code_value(codeField)
|
||||
% Преобразует значение поля Options в строку
|
||||
if ischar(codeField)
|
||||
value = codeField;
|
||||
elseif isstring(codeField)
|
||||
value = char(codeField);
|
||||
elseif iscell(codeField)
|
||||
value = strjoin(codeField, newline);
|
||||
else
|
||||
warning('Неподдерживаемый тип данных: сохранено как пустая строка');
|
||||
value = '';
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function res = addCodeBat(codeConfig, codePath)
|
||||
% Возвращает 0 при успехе, 1 при ошибке
|
||||
try
|
||||
% Формируем строки
|
||||
srcText = compiler.createSourcesBat('code_PERIPH', codeConfig.Sources.Options, periphPath);
|
||||
incText = compiler.createIncludesBat('includes_PERIPH', codeConfig.Includes.Options, periphPath);
|
||||
srcText = compiler.createSourcesBat('code_PERIPH', codeConfig.Sources, codePath);
|
||||
incText = compiler.createIncludesBat('includes_PERIPH', codeConfig.Includes, codePath);
|
||||
|
||||
% Записываем результат
|
||||
res = compiler.updateRunMexBat(srcText, incText, ':: PERIPH BAT'); % Всё прошло успешно
|
||||
@ -229,7 +432,7 @@ classdef periphConfig
|
||||
end
|
||||
|
||||
|
||||
function res = addUserCodeConfig(userCodeConfig)
|
||||
function res = addUserFunctions(userCodeConfig)
|
||||
% userCodeConfig — структура config.UserCode
|
||||
|
||||
initFuncsText = '';
|
||||
@ -258,7 +461,7 @@ classdef periphConfig
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function res = updateWrapperCode(initFuncsText, simFuncsText, deinitFuncsText)
|
||||
% Входные параметры:
|
||||
% srcText - текст для записи set code_...
|
||||
@ -378,9 +581,9 @@ classdef periphConfig
|
||||
else
|
||||
param.Alias = def.Def;
|
||||
end
|
||||
else
|
||||
param.Callback = 'periphConfig.update_callback();';
|
||||
end
|
||||
|
||||
param.Callback = 'periphConfig.update_callback();';
|
||||
end
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user