Compare commits

..

No commits in common. "abdf0f1e50b56de61fac8d2c99e63ff6a2ae5e64" and "245592a8216f038d4f79812abacb7d7d5bcd2d2b" have entirely different histories.

13 changed files with 362 additions and 854 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,156 +0,0 @@
classdef appWrap
methods(Static)
function appWrapperFunc()
block = gcb;
% Получаем имя функции и путь к файлам
[filename, section, tool, example]= appWrap.getAppWrapperUserFile(block);
mcuMask.tool(tool, example);
% Загружаем содержимое файла
set_param(block, 'appWrapperCode', '');
try
code = fileread(filename);
code = regexprep(code, '\r\n?', '\n'); % нормализуем окончания строк
includesText = editCode.extractSection(code, section);
set_param(block, 'appWrapperCode', includesText);
catch
end
% % Поиск тела обычной функции
% expr = sprintf('void %s()', sel);
% funcBody = editCode.extractSection(code, expr);
% set_param(block, 'wrapperCode', funcBody);
end
function saveAppWrapperCode()
block = gcb;
% Получаем имя функции и путь к файлам
[filename, section] = appWrap.getAppWrapperUserFile(block);
if ~isfile(filename)
errordlg(['Файл не найден: ', filename]);
return;
end
sel = get_param(block, 'appWrapperFunc');
basePath = get_param(block, 'appWrapperPath');
if isempty(basePath)
errordlg('Не указан путь к файлам обёртки (wrapperPath).');
return;
end
newBody = get_param(block, 'appWrapperCode');
code = fileread(filename);
code = regexprep(code, '\r\n?', '\n');
newBody = strrep(newBody, '\', '\\');
code = editCode.insertSection(code, section, newBody);
% else
% % Обновляем тело функции
% expr = sprintf('void %s()', sel);
% code = editCode.insertSection(code, expr, newBody);
% end
fid = fopen(filename, 'w', 'n', 'UTF-8');
if fid == -1
errordlg('Не удалось открыть файл для записи');
return;
end
fwrite(fid, code);
fclose(fid);
mcuMask.disp(1, ['Обновлено: ' sel]);
end
function openAppWrapperCode()
block = gcb;
% Получаем имя функции и путь к файлам
filename = appWrap.getAbsolutePath(mcuMask.getAppWrapperUserFile(block));
if exist(filename, 'file') == 2
% Формируем команду без кавычек
cmd = sprintf('rundll32.exe shell32.dll,OpenAs_RunDLL %s', filename);
status = system(cmd);
if status ~= 0
errordlg('Не удалось открыть окно выбора приложения.');
end
else
errordlg('Файл не найден');
end
end
end
%% SPECIFIC TOOLS
methods(Static, Access = private)
function [filename, section, tool, example] = getAppWrapperUserFile(block)
sel = get_param(block, 'appWrapperFunc');
basePath = mcuPath.get('appWrapperPath');
if isempty(basePath)
errordlg('Не указан путь к файлам обёртки (wrapperPath).');
return;
end
% Формируем путь к файлу в зависимости от типа запроса
if strcmp(sel, 'Includes')
filename = fullfile(basePath, 'app_includes.h');
section = '// INCLUDES';
tool = 'Инклюды для доступа к коду МК в коде оболочке';
example = '#include "main.h"';
elseif strcmp(sel, 'Dummy')
filename = fullfile(basePath, 'app_wrapper.c');
section = '// DUMMY';
tool = 'Заглушки для различных функций и переменных';
example = ['CAN_HandleTypeDef hcan = {0};' newline...
'void hardware_func(handle *huart) {}' newline...
'int wait_for_hardware_flag(int *flag) {' newline...
' return 1;' newline...
'}' newline...
''];
elseif strcmp(sel, 'App Init')
filename = fullfile(basePath, 'app_init.c');
section = '// USER APP INIT';
tool = ['Код для инициализации приложения МК.' newline newline...
'Вызов функций инициализации, если не используется отдельный поток для main().'];
example = 'init_func();';
elseif strcmp(sel, 'App Step')
filename = fullfile(basePath, 'app_wrapper.c');
section = '// USER APP STEP';
tool = ['Код приложения МК для вызова в шаге симуляции.' newline newline ...
'Вызов функций программы МК, если не используется отдельный поток для main().'];
example = 'step_func();';
elseif strcmp(sel, 'App Inputs')
filename = fullfile(basePath, 'app_io.c');
section = '// USER APP INPUT';
tool = ['Работа с буффером для портов S-Function' newline newline ...
'Буфер в начале хранит входные порты S-Function, далее идут выходные порты:' newline ...
'Buffer[0:15] - входной порт, Buffer[16:31] - входной 1 порт, ' newline ...
'Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт'];
example = ['// чтение 1-го элемента 0-го входного массива' newline...
'app_variable_2 = ReadInputArray(0, 1);' newline newline...
'// запись в буфер выходов' newline ...
'app_variable_2 = Buffer[10];'];
elseif strcmp(sel, 'App Outputs')
filename = fullfile(basePath, 'app_io.c');
section = '// USER APP OUTPUT';
tool = ['Работа с буффером для портов S-Function' newline newline ...
'Буфер в начале хранит входные порты S-Function, далее идут выходные порты:' newline ...
'Buffer[0:15] - входной порт, Buffer[16:31] - входной 1 порт, ' newline ...
'Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт'];
example = ['// запись в 1-й элемент 0-го выходного массива' newline...
'WriteOutputArray(app_variable, 0, 1);' newline newline ...
'// запись в буфер выходов' newline ...
'Buffer[XD_OUTPUT_START + 10] = app_variable_2;'];
elseif strcmp(sel, 'App Deinit')
filename = fullfile(basePath, 'app_init.c');
section = '// USER APP DEINIT';
tool = ['Код для деинициализации приложения МК.' newline newline ...
'Можно деинициализировать приложение МК, для повторного запуска.'];
example = 'memset(&htim1, sizeof(htim1), 0;';
else
tool = '';
mcuMask.disp(0, '\nОшибка выбора типа секции кода: неизвестное значение');
end
end
end
end

View File

@ -39,7 +39,7 @@ classdef asynchManage < handle
methods (Access = private) methods (Access = private)
function saveCallback(obj) function saveCallback(obj)
try try
mcuMask.close(obj.maskBlockPath); mcuMask.saveAndClose(obj.maskBlockPath);
save_system(obj.modelName); save_system(obj.modelName);
catch ME catch ME
warning('progr:Nneg', 'Ошибка при сохранении модели: %s', ME.message); warning('progr:Nneg', 'Ошибка при сохранении модели: %s', ME.message);
@ -79,7 +79,7 @@ classdef asynchManage < handle
function GUIconfigCallback(obj) function GUIconfigCallback(obj)
try try
mcuMask.close(obj.maskBlockPath); mcuMask.saveAndClose(obj.maskBlockPath);
mexing(0); mexing(0);
catch ME catch ME
warning('progr:Nneg', 'Ошибка при обновлении модели: %s', ME.message); warning('progr:Nneg', 'Ошибка при обновлении модели: %s', ME.message);

View File

@ -26,11 +26,10 @@ classdef compiler
% Список заголовочных файлов (.h) % Список заголовочных файлов (.h)
includes = { '.\' includes = { '.\'
}; };
wrapperPath = mcuPath.get('wrapperPath'); periphPath = mcuPath.get('wrapperPath');
% [wrapperPath, ~, ~] = fileparts(wrapperPath);
% Формируем строки % Формируем строки
wrapperSrcText = compiler.createSourcesBat('code_WRAPPER', sources, wrapperPath); wrapperSrcText = compiler.createSourcesBat('code_WRAPPER', sources, periphPath);
wrapperIncText = compiler.createIncludesBat('includes_WRAPPER', includes, wrapperPath); wrapperIncText = compiler.createIncludesBat('includes_WRAPPER', includes, periphPath);
% Записываем результат % Записываем результат
res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: WRAPPER BAT'); % Всё прошло успешно res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: WRAPPER BAT'); % Всё прошло успешно
@ -55,7 +54,7 @@ classdef compiler
% Записываем результат % Записываем результат
res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: APP WRAPPER BAT'); % Всё прошло успешно res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: APP WRAPPER BAT'); % Всё прошло успешно
periphConfig.updatePeriphRunMexBat();
end end

View File

@ -8,15 +8,13 @@ classdef customtable
tableControl = mask.getDialogControl(table_name); tableControl = mask.getDialogControl(table_name);
tableParameter = mask.getParameter(table_name); tableParameter = mask.getParameter(table_name);
nCols = tableControl.getNumberOfColumns; nCols = tableControl.getNumberOfColumns;
% инициализация колонок если они пустые % if nCols > 0
% такое случается при removeParameter % for i = 1:nCols
if isempty(tableControl.Columns) || (nCols > 1) % tableControl.removeColumn(1);
for i = 1:nCols % end
tableControl.removeColumn(1); % end
end % column = tableControl.addColumn(Name='Title', Type='edit');
column = tableControl.addColumn(Name='Title', Type='edit'); % tableControl.Sortable = 'on';
tableControl.Sortable = 'on';
end
column.Name = tableParameter.Alias; column.Name = tableParameter.Alias;
end end

View File

@ -1,72 +0,0 @@
classdef mainWrap
methods(Static)
function enableThreading()
block = gcb;
maskNames = get_param(block, 'MaskNames');
maskValues = get_param(block, 'MaskValues');
maskEnables = get_param(block, 'MaskEnables');
idxEnable = find(strcmp(maskNames, 'enableThreading'));
idxEdit = find(strcmp(maskNames, 'threadCycles'));
if isempty(idxEnable) || isempty(idxEdit)
error('Параметры enableThreading или threadCycles не найдены в маске');
end
val = maskValues{idxEnable};
if strcmp(val, 'on')
maskEnables{idxEdit} = 'on';
else
maskEnables{idxEdit} = 'off';
end
set_param(block, 'MaskEnables', maskEnables);
end
function enableDeinit()
block = gcb;
maskNames = get_param(block, 'MaskNames');
maskValues = get_param(block, 'MaskValues');
maskEnables = get_param(block, 'MaskEnables');
idxEnable = find(strcmp(maskNames, 'enableThreading'));
idxEdit = find(strcmp(maskNames, 'threadCycles'));
if isempty(idxEnable) || isempty(idxEdit)
error('Параметры enableThreading или threadCycles не найдены в маске');
end
val = maskValues{idxEnable};
if strcmp(val, 'on')
maskEnables{idxEdit} = 'on';
else
maskEnables{idxEdit} = 'off';
end
set_param(block, 'MaskEnables', maskEnables);
end
function extConsol()
block = gcb;
mask = Simulink.Mask.get(block);
fullOut = mask.getParameter('fullOutput');
extCons = mask.getParameter('extConsol');
if isempty(extCons) || isempty(fullOut)
error('Параметры fullOutput или extConsol не найдены в маске');
end
if(strcmp(extCons.Enabled, 'on'))
if strcmp(extCons.Value, 'on')
fullOut.Enabled = 'off';
fullOut.Value = 'on';
else
fullOut.Enabled = 'on';
end
else
fullOut.Enabled = 'on';
end
end
end
%% SPECIFIC TOOLS
methods(Static, Access = private)
end
end

View File

@ -1,5 +1,5 @@
classdef mcuMask classdef mcuMask
%% CALLBACKS
methods(Static) methods(Static)
% Following properties of 'maskInitContext' are avalaible to use: % Following properties of 'maskInitContext' are avalaible to use:
% - BlockHandle % - BlockHandle
@ -58,37 +58,148 @@ classdef mcuMask
end end
%% WRAPPER PARAMS %% WRAPPER PARAMS
function enableThreading(callbackContext)
block = gcb;
maskNames = get_param(block, 'MaskNames');
maskValues = get_param(block, 'MaskValues');
maskEnables = get_param(block, 'MaskEnables');
idxEnable = find(strcmp(maskNames, 'enableThreading'));
idxEdit = find(strcmp(maskNames, 'threadCycles'));
if isempty(idxEnable) || isempty(idxEdit)
error('Параметры enableThreading или threadCycles не найдены в маске');
end
val = maskValues{idxEnable};
if strcmp(val, 'on')
maskEnables{idxEdit} = 'on';
else
maskEnables{idxEdit} = 'off';
end
set_param(block, 'MaskEnables', maskEnables);
end
function enableDeinit(callbackContext)
block = gcb;
maskNames = get_param(block, 'MaskNames');
maskValues = get_param(block, 'MaskValues');
maskEnables = get_param(block, 'MaskEnables');
idxEnable = find(strcmp(maskNames, 'enableThreading'));
idxEdit = find(strcmp(maskNames, 'threadCycles'));
if isempty(idxEnable) || isempty(idxEdit)
error('Параметры enableThreading или threadCycles не найдены в маске');
end
val = maskValues{idxEnable};
if strcmp(val, 'on')
maskEnables{idxEdit} = 'on';
else
maskEnables{idxEdit} = 'off';
end
set_param(block, 'MaskEnables', maskEnables);
end
function extConsol(callbackContext)
block = gcb;
mask = Simulink.Mask.get(block);
fullOut = mask.getParameter('fullOutput');
extCons = mask.getParameter('extConsol');
if isempty(extCons) || isempty(fullOut)
error('Параметры fullOutput или extConsol не найдены в маске');
end
if(strcmp(extCons.Enabled, 'on'))
if strcmp(extCons.Value, 'on')
fullOut.Enabled = 'off';
fullOut.Value = 'on';
else
fullOut.Enabled = 'on';
end
else
fullOut.Enabled = 'on';
end
end
function wrapperPath_add(callbackContext) function wrapperPath_add(callbackContext)
mcuPath.addPath('wrapperPath'); mcuPath.addPath('wrapperPath');
end end
function enableThreading(callbackContext)
mainWrap.enableThreading();
end
function enableDeinit(callbackContext)
mainWrap.enableDeinit();
end
function extConsol(callbackContext)
mainWrap.extConsol();
end
%% USER WRAPPER CODE
function appWrapperPath_add(callbackContext) function appWrapperPath_add(callbackContext)
mcuPath.addPath('appWrapperPath'); mcuPath.addPath('appWrapperPath');
end end
%% USER WRAPPER CODE
function appWrapperFunc(callbackContext) function appWrapperFunc(callbackContext)
appWrap.appWrapperFunc(); block = gcb;
% Получаем имя функции и путь к файлам
[filename, section, tool, example]= mcuMask.getWrapperUserFile(block);
mcuMask.tool(tool, example);
% Загружаем содержимое файла
set_param(block, 'appWrapperCode', '');
try
code = fileread(filename);
code = regexprep(code, '\r\n?', '\n'); % нормализуем окончания строк
includesText = editCode.extractSection(code, section);
set_param(block, 'appWrapperCode', includesText);
catch
end
% % Поиск тела обычной функции
% expr = sprintf('void %s()', sel);
% funcBody = editCode.extractSection(code, expr);
% set_param(block, 'wrapperCode', funcBody);
end end
function saveAppWrapperCode(callbackContext) function saveAppWrapperCode(callbackContext)
appWrap.saveAppWrapperCode(); block = gcb;
% Получаем имя функции и путь к файлам
[filename, section] = mcuMask.getWrapperUserFile(block);
if ~isfile(filename)
errordlg(['Файл не найден: ', filename]);
return;
end
sel = get_param(block, 'appWrapperFunc');
basePath = get_param(block, 'appWrapperPath');
if isempty(basePath)
errordlg('Не указан путь к файлам обёртки (wrapperPath).');
return;
end
newBody = get_param(block, 'appWrapperCode');
code = fileread(filename);
code = regexprep(code, '\r\n?', '\n');
newBody = strrep(newBody, '\', '\\');
code = editCode.insertSection(code, section, newBody);
% else
% % Обновляем тело функции
% expr = sprintf('void %s()', sel);
% code = editCode.insertSection(code, expr, newBody);
% end
fid = fopen(filename, 'w', 'n', 'UTF-8');
if fid == -1
errordlg('Не удалось открыть файл для записи');
return;
end
fwrite(fid, code);
fclose(fid);
mcuMask.disp(1, ['Обновлено: ' sel]);
end end
function openAppWrapperCode(callbackContext) function openAppWrapperCode(callbackContext)
appWrap.openAppWrapperCode(); block = gcb;
% Получаем имя функции и путь к файлам
filename = mcuPath.getAbsolutePath(mcuMask.getWrapperUserFile(block));
if exist(filename, 'file') == 2
% Формируем команду без кавычек
cmd = sprintf('rundll32.exe shell32.dll,OpenAs_RunDLL %s', filename);
status = system(cmd);
if status ~= 0
errordlg('Не удалось открыть окно выбора приложения.');
end
else
errordlg('Файл не найден');
end
end end
%% USER CODE %% USER CODE
@ -109,23 +220,36 @@ classdef mcuMask
end end
%% PERIPH CONFIG %% PERIPH CONFIG
function periphPath_add(callbackContext) function periphPath_add(callbackContext)
mcuPath.addAnyFile('periphPath'); mcuPath.addAnyFile('periphPath');
end end
function periphUpdate(callbackContext)
modelName = bdroot(gcb); % получить имя верхнего уровня модели
blockName = gcb;
mgr = asynchManage(modelName, blockName); % создать объект класса
mgr.updateGUIfromConfig(); % запустить сохранение и обновление
end
%% COMPILE %% COMPILE
function compile(callbackContext) function compile(callbackContext)
compiler.compile(); compiler.compile();
end end
function setSFuncName(callbackContext)
function updateModel(callbackContext)
addpath(mcuPath.get('wrapperPath'));
res = mexing(1);
if res ~= 0
return;
end
modelName = bdroot(gcb); % получить имя верхнего уровня модели
blockName = gcb;
mgr = asynchManage(modelName, blockName); % создать объект класса
mgr.saveAndUpdateModel(); % запустить сохранение и обновление
end
function findjobj_link(callbackContext)
web('https://www.mathworks.com/matlabcentral/fileexchange/14317-findjobj-find-java-handles-of-matlab-graphic-objects');
end
function set_name(callbackContext)
block = gcb; block = gcb;
% Получаем параметр имени S-Function из маски блока % Получаем параметр имени S-Function из маски блока
newName = mcuMask.get_name(); newName = mcuMask.get_name();
@ -158,30 +282,88 @@ classdef mcuMask
fwrite(fid, updatedText); fwrite(fid, updatedText);
fclose(fid); fclose(fid);
end end
end
%% SPECIFIC TOOLS
methods(Static, Access = private)
function [filename, section, tool, example] = getWrapperUserFile(block)
sel = get_param(block, 'appWrapperFunc');
basePath = mcuPath.get('appWrapperPath');
if isempty(basePath)
errordlg('Не указан путь к файлам обёртки (wrapperPath).');
return;
end
% Формируем путь к файлу в зависимости от типа запроса
if strcmp(sel, 'Includes')
filename = fullfile(basePath, 'app_includes.h');
section = '// INCLUDES';
tool = 'Инклюды для доступа к коду МК в коде оболочке';
example = '#include "main.h"';
elseif strcmp(sel, 'Dummy')
filename = fullfile(basePath, 'app_wrapper.c');
section = '// DUMMY';
tool = 'Заглушки для различных функций и переменных';
example = ['CAN_HandleTypeDef hcan = {0};' newline...
'void hardware_func(handle *huart) {}' newline...
'int wait_for_hardware_flag(int *flag) {' newline...
' return 1;' newline...
'}' newline...
''];
elseif strcmp(sel, 'App Init')
filename = fullfile(basePath, 'app_init.c');
section = '// USER APP INIT';
tool = ['Код для инициализации приложения МК.' newline newline...
'Вызов функций инициализации, если не используется отдельный поток для main().'];
example = 'init_func();';
elseif strcmp(sel, 'App Step')
filename = fullfile(basePath, 'app_wrapper.c');
section = '// USER APP STEP';
tool = ['Код приложения МК для вызова в шаге симуляции.' newline newline ...
'Вызов функций программы МК, если не используется отдельный поток для main().'];
example = 'step_func();';
elseif strcmp(sel, 'App Inputs')
filename = fullfile(basePath, 'app_io.c');
section = '// USER APP INPUT';
tool = ['Работа с буффером для портов S-Function' newline newline ...
'Буфер в начале хранит входные порты S-Function, далее идут выходные порты:' newline ...
'Buffer[0:15] - входной порт, Buffer[16:31] - входной 1 порт, ' newline ...
'Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт'];
example = ['// чтение 1-го элемента 0-го входного массива' newline...
'app_variable_2 = ReadInputArray(0, 1);' newline newline...
'// запись в буфер выходов' newline ...
'app_variable_2 = Buffer[10];'];
elseif strcmp(sel, 'App Outputs')
filename = fullfile(basePath, 'app_io.c');
section = '// USER APP OUTPUT';
tool = ['Работа с буффером для портов S-Function' newline newline ...
'Буфер в начале хранит входные порты S-Function, далее идут выходные порты:' newline ...
'Buffer[0:15] - входной порт, Buffer[16:31] - входной 1 порт, ' newline ...
'Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт'];
example = ['// запись в 1-й элемент 0-го выходного массива' newline...
'WriteOutputArray(app_variable, 0, 1);' newline newline ...
'// запись в буфер выходов' newline ...
'Buffer[XD_OUTPUT_START + 10] = app_variable_2;'];
elseif strcmp(sel, 'App Deinit')
filename = fullfile(basePath, 'app_init.c');
section = '// USER APP DEINIT';
tool = ['Код для деинициализации приложения МК.' newline newline ...
'Можно деинициализировать приложение МК, для повторного запуска.'];
example = 'memset(&htim1, sizeof(htim1), 0;';
else
tool = '';
mcuMask.disp(0, '\nОшибка выбора типа секции кода: неизвестное значение');
end
%% LINK TO EXTERNAL CONSOLE
function findjobj_link(callbackContext)
web https://www.mathworks.com/matlabcentral/fileexchange/14317-findjobj-find-java-handles-of-matlab-graphic-objects;
end end
end end
%% GENERAL TOOLS %% GENERAL TOOLS
methods(Static, Access = public) methods(Static, Access = public)
function updateModel() function saveAndClose(blockPath)
addpath(mcuPath.get('wrapperPath'));
res = mexing(1);
if res ~= 0
return;
end
modelName = bdroot(gcb); % получить имя верхнего уровня модели
blockName = gcb;
mgr = asynchManage(modelName, blockName); % создать объект класса
mgr.saveAndUpdateModel(); % запустить сохранение и обновление
end
function close(blockPath)
try try
% Считываем текущее имя модели % Считываем текущее имя модели
modelName = bdroot(blockPath); modelName = bdroot(blockPath);
@ -301,12 +483,8 @@ classdef mcuMask
end 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]); set_param(gcb, 'consoleOutput', [out_now out]);
end end
end
function updateModelAsync() function updateModelAsync()

View File

@ -1,13 +1,13 @@
classdef mcuPath classdef mcuPath
methods(Static) methods(Static)
%% GET PATH FROM PARAM
function path = get(paramName) function path = get(paramName)
blockPath = gcb; blockPath = gcb;
path = get_param(blockPath, paramName); path = get_param(blockPath, paramName);
end end
%% ADD PATH TO TABLE
function addSourceFileTable(targetParamName, message) function addSourceFileTable(targetParamName, message)
% Открываем проводник для выбора файлов % Открываем проводник для выбора файлов
@ -61,7 +61,6 @@ classdef mcuPath
customtable.collect(targetParamName, oldTable); customtable.collect(targetParamName, oldTable);
end end
%% ADD PATH TO EDIT
function addPath(targetParamName, message) function addPath(targetParamName, message)
block = gcb; block = gcb;
@ -92,8 +91,6 @@ classdef mcuPath
param.Value = rel; param.Value = rel;
end end
%% GET PATH STRING
function absPath = getAbsolutePath(relPath) function absPath = getAbsolutePath(relPath)
% relativeToAbsolutePath преобразует относительный путь в абсолютный. % relativeToAbsolutePath преобразует относительный путь в абсолютный.
% %
@ -118,6 +115,8 @@ classdef mcuPath
end end
end end
function rel = absoluteToRelativePath(pathstr) function rel = absoluteToRelativePath(pathstr)
% absoluteToRelativePath преобразует абсолютный путь в относительный от текущей директории. % absoluteToRelativePath преобразует абсолютный путь в относительный от текущей директории.
% %
@ -164,5 +163,6 @@ classdef mcuPath
end end
end end
end end
end end

View File

@ -69,7 +69,7 @@ function res = mexing(compile_mode)
config = periphConfig.read_config(blockPath); config = periphConfig.read_config(blockPath);
config = periphConfig.update_config(blockPath, config); config = periphConfig.update_config(blockPath, config);
periphConfig.write_config(config); periphConfig.write_config(config);
periphConfig.updateMask(blockPath, config); periphConfig.update(blockPath, config);
end end
end end
@ -202,8 +202,6 @@ function definesWrapperArg = buildConfigDefinesString()
definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0); definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0);
case 'edit' case 'edit'
definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1); definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1);
case 'popup'
definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0);
otherwise otherwise
% Необрабатываемые типы % Необрабатываемые типы
end end
@ -232,15 +230,7 @@ function definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, val_
end end
% Берём alias из маски % Берём alias из маски
if ~strcmp(param.Type, 'popup') alias = param.Alias;
def_name = param.Alias;
else
def_name = param.Value;
end
if strcmp(def_name, '')
return;
end
if val_define ~= 0 if val_define ~= 0
% Значение параметра % Значение параметра
@ -250,16 +240,14 @@ function definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, val_
val = num2str(val); % Преобразуем результат в строку val = num2str(val); % Преобразуем результат в строку
end end
% Формируем define с кавычками и значением % Формируем define с кавычками и значением
newDefine = ['-D"' def_name '__EQ__' val '"']; newDefine = ['-D"' alias '__EQ__' val '"'];
elseif ~strcmp(param.Type, 'popup') else
if mcuMask.read_checkbox(paramName) if mcuMask.read_checkbox(paramName)
% Формируем define с кавычками без значения % Формируем define с кавычками без значения
newDefine = ['-D"' def_name '"']; newDefine = ['-D"' alias '"'];
else else
newDefine = ''; newDefine = '';
end end
else
newDefine = ['-D"' def_name '"'];
end end

View File

@ -1,215 +1,82 @@
classdef periphConfig classdef periphConfig
methods(Static) methods(Static)
function updateMask(blockPath, config) function update(blockPath, config)
% blockPath = [blockPath '/MCU']; % blockPath = [blockPath '/MCU'];
% Проверяем, была ли маска открыта % Проверяем, была ли маска открыта
% wasOpen = isMaskDialogOpen(blockPath); % wasOpen = isMaskDialogOpen(blockPath);
mask = Simulink.Mask.get(blockPath); mask = Simulink.Mask.get(blockPath);
periphPath = mcuPath.get('periphPath');
[periphPath, ~, ~] = fileparts(periphPath);
tableNames = {'incTable', 'srcTable'}; tableNames = {'incTable', 'srcTable'};
columns_backup = customtable.save_all_tables(tableNames); columns_backup = customtable.save_all_tables(tableNames);
try
rowWidth = str2double(get_param(blockPath, 'rowWidth'));
containerName = 'configTabAll'; containerName = 'configTabAll';
periphConfig.clear_all_from_container(mask, containerName); periphConfig.clear_all_from_container(mask, containerName);
% Ищем контейнер, в который будем добавлять вкладки % Ищем контейнер, в который будем добавлять вкладки
container = mask.getDialogControl(containerName); container = mask.getDialogControl(containerName);
if isempty(container) if isempty(container)
error('Контейнер "%s" не найден в маске.', containerName); error('Контейнер "%s" не найден в маске.', containerName);
end
if ~isempty(config)
if isfield(config, 'Code')
res = periphConfig.addCodeConfig(config.Code, periphPath);
if res == 0
error('Ошибка: неудачное добавление кода периферии. Проверьте корректность файлов и путей в конфигурационном файле')
end
else
error('Ошибка: в конфигурационном файле не задан исходный код для симуляции периферии')
end end
if ~isempty(config) if isfield(config, 'UserCode')
% Проходим по каждому модулю (ADC, TIM...) res = periphConfig.addUserCodeConfig(config.UserCode);
periphs = fieldnames(config); if res == 0
for i = 1:numel(periphs) error('Ошибка: неудачное добавление функций для симуляции. Проверьте корректность названий функций в конфигурационном файле')
periph = periphs{i}; end
else
error('Ошибка: в конфигурационном файле не заданы функции для симуляции периферии')
end
% Сохраняем код, если он есть % Проходим по каждому модулю (ADC, TIM...)
periphConfig.store_single_periph_code(mask, periph, config.(periph)); periphs = fieldnames(config);
for i = 1:numel(periphs)
periph = periphs{i};
% Проверяем наличие Defines % Пропускаем Code и UserCode, они уже обработаны
if ~isfield(config.(periph), 'Defines') if strcmp(periph, 'Code') || strcmp(periph, 'UserCode')
continue; continue;
end end
defines = config.(periph).Defines; defines = config.(periph).Defines;
defNames = fieldnames(defines); defNames = fieldnames(defines);
% Создаём вкладку для модуля % Создаём вкладку для модуля
tabCtrl = container.addDialogControl('tab', periph); tabCtrl = container.addDialogControl('tab', periph);
tabCtrl.Prompt = [periph ' Config']; tabCtrl.Prompt = [periph ' Config'];
rowCountMap = containers.Map(); for j = 1:numel(defNames)
for j = 1:numel(defNames) defPrompt = defNames{j};
defPrompt = defNames{j}; def = defines.(defPrompt);
def = defines.(defPrompt);
% Вызов функции добавления одного параметра % Вызов функции добавления одного параметра
periphConfig.addConfig(mask, containerName, periph, defPrompt, def, rowCountMap, rowWidth); periphConfig.addDefineConfig(mask, containerName, periph, defPrompt, def);
end
end 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 end
% Восстанавливаем таблицы
customtable.restore_all_tables(tableNames, columns_backup);
% % Повторно открываем маску, если она была открыта % % Повторно открываем маску, если она была открыта
% if wasOpen % if wasOpen
% open_system(blockPath, 'mask'); % open_system(blockPath, 'mask');
% end % end
end end
function update()
blockPath = gcb;
mask = Simulink.Mask.get(blockPath);
config = periphConfig.read_config(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
catch
warning('Вкладка с именем "%s" не найдена.', periph);
end
else
% Чекбокса нет просто пытаемся включить вкладку, если она есть
try
tab = container.getDialogControl(periph);
tab.Enabled = 'on';
% Опционально можно синхронизировать параметры, если есть config поле
if isfield(config, periph)
periphConfig.sync_tab_params(mask, config.(periph), periph);
end
catch
% Можно не выводить предупреждение вкладка может быть необязательной
% warning('Вкладка с именем "%s" не найдена.', periph);
end
end
end
end
function periphParamCallback(paramName)
blockPath = gcb;
mask = Simulink.Mask.get(blockPath);
hObj = mask.getParameter(paramName);
config = periphConfig.read_config(blockPath);
container = mask.getDialogControl('configTabAll');
% === Проверка на Tab_<Periph>_Enable ===
exprTab = '^Tab_(\w+)_Enable$';
tokensTab = regexp(paramName, exprTab, 'tokens');
if ~isempty(tokensTab)
periph = tokensTab{1}{1};
try
tab = container.getDialogControl(periph);
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);
end
end
catch
warning('Ошибка обработки вкладки "%s".', periph);
end
return;
end
% === Проверка на параметр, связанный с Sources/Includes ===
% Проверка: это параметр, у которого есть соответствующий Hidden_<Name>_Sources или Hidden_<Name>_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 = periphConfig.get_field(config, nameBase);
catch
warning('Не удалось найти путь %s в config.', nameBase);
return;
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
blockPath = gcb;
CodeStruct = periphConfig.restore_periph_code_from_mask(blockPath);
periphPath = mcuPath.get('periphPath');
[periphPath, ~, ~] = fileparts(periphPath);
periphConfig.addCodeBat(CodeStruct, periphPath);
end
function config = update_config(blockPath, config) function config = update_config(blockPath, config)
if isempty(config) if isempty(config)
return; return;
@ -300,231 +167,19 @@ classdef periphConfig
end end
end end
methods(Static, Access=private) methods(Static, Access=private)
function clear_tab_params(mask, configStruct, prefix, depth) function res = addCodeConfig(codeConfig, periphPath)
if nargin < 4
depth = 0;
end
maxDepth = 3; % Максимальная глубина рекурсии
fields = fieldnames(configStruct);
for i = 1:numel(fields)
key = fields{i};
value = configStruct.(key);
paramName = [prefix '_' key];
if isstruct(value)
if depth < maxDepth
% Рекурсивный вызов для вложенных структур с увеличением глубины
periphConfig.clear_tab_params(mask, value, paramName, depth + 1);
end
else
if strcmp(key, 'Sources') || strcmp(key, 'Includes')
baseName = periphConfig.get_final_name_from_prefix(prefix);
periphConfig.clear_single_periph_code_param(mask, baseName);
end
end
end
end
function sync_tab_params(mask, configStruct, prefix, depth)
if nargin < 4
depth = 0;
end
maxDepth = 3; % Максимальная глубина рекурсии
fields = fieldnames(configStruct);
for i = 1:numel(fields)
key = fields{i};
value = configStruct.(key);
paramName = [prefix '_' key];
if isstruct(value)
if depth < maxDepth
% Рекурсивный вызов для вложенных структур с увеличением глубины
periphConfig.sync_tab_params(mask, value, paramName, depth + 1);
end
else
if strcmp(key, 'Sources') || strcmp(key, 'Includes')
baseName = periphConfig.get_final_name_from_prefix(prefix);
periphConfig.store_single_periph_code(mask, baseName, configStruct);
end
end
end
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)
tab = container.addDialogControl('tab', tabName);
tab.Prompt = 'Hidden Code Settings';
tab.Visible = 'off';
else
tab.Visible = 'off';
end
% Запуск рекурсивного обхода
periphConfig.process_struct_recursive(mask, tabName, config, {}, existingParams);
end
function process_struct_recursive(mask, tabName, currentStruct, nameStack, existingParams)
fields = fieldnames(currentStruct);
for i = 1:numel(fields)
fieldName = fields{i};
value = currentStruct.(fieldName);
newStack = [nameStack, fieldName]; % Добавляем уровень к имени
% Если value структура, обходим дальше
if isstruct(value)
% Проверяем: это структура с Sources/Includes или просто промежуточный узел?
hasSources = isfield(value, 'Sources');
hasIncludes = isfield(value, 'Includes');
if hasSources
periphConfig.addHiddenParam(mask, tabName, fieldName, 'Sources', existingParams);
end
if hasIncludes
periphConfig.addHiddenParam(mask, tabName, fieldName, 'Includes', existingParams);
end
% Рекурсивно продолжаем обход
periphConfig.process_struct_recursive(mask, tabName, value, newStack, existingParams);
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_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);
% Удаляем все параметры
for i = 1:numel(paramsToDelete)
try
mask.removeParameter(paramsToDelete{i});
catch
warning('Не удалось удалить параметр %s', paramsToDelete{i});
end
end
% Рекурсивно удалить все вкладки внутри контейнера
mcuMask.delete_all_tabs(mask, container);
end
function res = addCodeBat(codeConfig, codePath)
% Добавить сурсы и пути в батник
% Возвращает 0 при успехе, 1 при ошибке % Возвращает 0 при успехе, 1 при ошибке
try try
% Формируем строки % Формируем строки
srcText = compiler.createSourcesBat('code_PERIPH', codeConfig.Sources, codePath); srcText = compiler.createSourcesBat('code_PERIPH', codeConfig.Sources.Options, periphPath);
incText = compiler.createIncludesBat('includes_PERIPH', codeConfig.Includes, codePath); incText = compiler.createIncludesBat('includes_PERIPH', codeConfig.Includes.Options, periphPath);
% Записываем результат % Записываем результат
res = compiler.updateRunMexBat(srcText, incText, ':: PERIPH BAT'); % Всё прошло успешно res = compiler.updateRunMexBat(srcText, incText, ':: PERIPH BAT'); % Всё прошло успешно
@ -534,8 +189,8 @@ classdef periphConfig
end end
end end
function res = addUserFunctions(userCodeConfig)
% Добавить функции и дефайны в исходный код wrapper function res = addUserCodeConfig(userCodeConfig)
% userCodeConfig структура config.UserCode % userCodeConfig структура config.UserCode
initFuncsText = ''; initFuncsText = '';
@ -545,26 +200,27 @@ classdef periphConfig
if isfield(userCodeConfig, 'Functions') if isfield(userCodeConfig, 'Functions')
funcs = userCodeConfig.Functions; funcs = userCodeConfig.Functions;
if isfield(funcs, 'PeriphInit') if isfield(funcs, 'PeriphInit') && isfield(funcs.PeriphInit, 'Options')
initFuncs = funcs.PeriphInit; initFuncs = funcs.PeriphInit.Options;
initFuncsText = strjoin(strcat('\t', initFuncs, ';'), '\n'); initFuncsText = strjoin(strcat('\t', initFuncs, ';'), '\n');
end end
if isfield(funcs, 'PeriphSimulation') if isfield(funcs, 'PeriphSimulation') && isfield(funcs.PeriphSimulation, 'Options')
simFuncs = funcs.PeriphSimulation; simFuncs = funcs.PeriphSimulation.Options;
simFuncsText = strjoin(strcat('\t', simFuncs, ';'), '\n'); simFuncsText = strjoin(strcat('\t', simFuncs, ';'), '\n');
end end
if isfield(funcs, 'PeriphDeinit') if isfield(funcs, 'PeriphDeinit') && isfield(funcs.PeriphDeinit, 'Options')
deinitFuncs = funcs.PeriphDeinit; deinitFuncs = funcs.PeriphDeinit.Options;
deinitFuncsText = strjoin(strcat('\t', deinitFuncs, ';'), '\n'); deinitFuncsText = strjoin(strcat('\t', deinitFuncs, ';'), '\n');
end end
res = periphConfig.writeWrapperCode(initFuncsText, simFuncsText, deinitFuncsText); res = periphConfig.updateWrapperCode(initFuncsText, simFuncsText, deinitFuncsText);
end end
end end
function res = writeWrapperCode(initFuncsText, simFuncsText, deinitFuncsText)
function res = updateWrapperCode(initFuncsText, simFuncsText, deinitFuncsText)
% Входные параметры: % Входные параметры:
% srcText - текст для записи set code_... % srcText - текст для записи set code_...
% incText - текст для записи set includes_... % incText - текст для записи set includes_...
@ -594,26 +250,16 @@ classdef periphConfig
end end
end end
function addConfig(mask, containerName, periphName, defPrompt, def, rowCountMap, rowWidth)
function addDefineConfig(mask, containerName, periphName, defPrompt, def)
% mask объект маски Simulink.Mask.get(blockPath) % mask объект маски Simulink.Mask.get(blockPath)
% containerName имя контейнера, в который добавляем параметр (например, 'configTabAll') % containerName имя контейнера, в который добавляем параметр (например, 'configTabAll')
% periphName имя вкладки / контейнера для текущего периферийного блока (например, 'ADC') % periphName имя вкладки / контейнера для текущего периферийного блока (например, 'ADC')
% defPrompt имя параметра в Defines (например, 'shift_enable') % defPrompt имя параметра в Defines (например, 'shift_enable')
% def структура с описанием параметра (Prompt, Def, Type, Default, NewRow и т.п.) % def структура с описанием параметра (Prompt, Def, Type, Default, NewRow и т.п.)
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
rowCount = 1;
end
rowCountMap(periphName) = rowCount;
% Найдем контейнер с таким именем % Найдем контейнер с таким именем
container = mask.getDialogControl(containerName); container = mask.getDialogControl(containerName);
if isempty(container) if isempty(container)
@ -690,109 +336,38 @@ classdef periphConfig
param.DialogControl.Row = 'current'; param.DialogControl.Row = 'current';
end end
if isfield(def, 'Def') if strcmp(paramType, 'popup')
if strcmp(paramType, 'popup') param.TypeOptions = def.Def;
param.TypeOptions = def.Def;
else
param.Alias = def.Def;
end
end
callback = sprintf('periphConfig.periphParamCallback("%s");', paramName);
param.Callback = callback;
end
%% ELEMENTARY
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')
paramName = ['Hidden_' char(periph) '_Sources'];
try
param = mask.getParameter(paramName);
param.Value = periphConfig.convert_code_value(code.Sources);
catch
mcuMask.disp(0, ['Параметр ' paramName ' не найден']);
end
end
% Сохраняем Includes, если они есть
if isfield(code, 'Includes')
paramName = ['Hidden_' periph '_Includes'];
try
param = mask.getParameter(paramName);
param.Value = periphConfig.convert_code_value(code.Includes);
catch
mcuMask.disp(0, ['Параметр ' paramName ' не найден']);
end
end
end
function value = get_field(configStruct, targetConfig)
% получить targetConfig структуру из конфига (для глубоко вложенных)
value = [];
fields = fieldnames(configStruct);
for i = 1:numel(fields)
key = fields{i};
if strcmp(key, targetConfig)
value = configStruct.(key);
return; % нашли и возвращаем
elseif isstruct(configStruct.(key))
value = periphConfig.get_field(configStruct.(key), targetConfig);
if ~isempty(value)
return; % нашли во вложенной структуре
end
end
end
% Если не нашли, можно выбросить ошибку или вернуть пустое
if isempty(value)
% error('Поле "%s" не найдено в структуре.', targetConfig);
end
end
function short = get_final_name_from_prefix(prefix)
% Берёт последнее имя после "_" (читаемое имя)
parts = strsplit(prefix, '_');
short = parts{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 else
% warning('Неподдерживаемый тип данных: сохранено как пустая строка'); param.Alias = def.Def;
value = '';
end end
end 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);
% Удаляем все параметры
for i = 1:numel(paramsToDelete)
try
mask.removeParameter(paramsToDelete{i});
catch
warning('Не удалось удалить параметр %s', paramsToDelete{i});
end
end
% Рекурсивно удалить все вкладки внутри контейнера
mcuMask.delete_all_tabs(mask, container);
end
function res = ternary(cond, valTrue, valFalse) function res = ternary(cond, valTrue, valFalse)
if cond if cond
res = valTrue; res = valTrue;

View File

@ -30,17 +30,15 @@ set defines_WRAPPER=-D"MATLAB"^ -D"__sizeof_ptr=8"
:: -------------------------WRAPPER PATHS AND CODE--------------------------- :: -------------------------WRAPPER PATHS AND CODE---------------------------
:: оболочка, которая будет моделировать работу МК в симулинке :: оболочка, которая будет моделировать работу МК в симулинке
:: WRAPPER BAT START set includes_WRAPPER=-I"."^
-I".\MCU_Wrapper"^
:: WRAPPER BAT END -I".\app_wrapper"
:: APP WRAPPER BAT START
:: APP WRAPPER BAT END
set includes_WRAPPER= %includes_WRAPPER% %includes_APP_WRAPPER%
set code_WRAPPER= %code_WRAPPER% %code_APP_WRAPPER%
set code_WRAPPER= .\MCU_Wrapper\MCU.c^
.\MCU_Wrapper\mcu_wrapper.c^
.\app_wrapper\app_init.c^
.\app_wrapper\app_io.c^
.\app_wrapper\app_wrapper.c
:: PERIPH BAT START :: PERIPH BAT START

View File

@ -1,5 +1,5 @@
<deployment-project plugin="plugin.toolbox" plugin-version="1.0"> <deployment-project plugin="plugin.toolbox" plugin-version="1.0">
<configuration build-checksum="2658716694" file="E:\.WORK\MATLAB\mcu_matlab\mcuwrapper.prj" location="E:\.WORK\MATLAB\mcu_matlab" name="mcuwrapper" target="target.toolbox" target-name="Package Toolbox"> <configuration build-checksum="1721556499" file="E:\.WORK\MATLAB\mcu_matlab\mcuwrapper.prj" location="E:\.WORK\MATLAB\mcu_matlab" name="mcuwrapper" target="target.toolbox" target-name="Package Toolbox">
<param.appname>MCU Wrapper</param.appname> <param.appname>MCU Wrapper</param.appname>
<param.authnamewatermark>Razvalyaev</param.authnamewatermark> <param.authnamewatermark>Razvalyaev</param.authnamewatermark>
<param.email>wot890089@mail.ru</param.email> <param.email>wot890089@mail.ru</param.email>