Compare commits
10 Commits
245592a821
...
abdf0f1e50
Author | SHA1 | Date | |
---|---|---|---|
abdf0f1e50 | |||
4c78383edf | |||
9d5cd30bb8 | |||
5a92e0bec0 | |||
982d29560f | |||
02379d4c46 | |||
0145ec818e | |||
7c2fb99908 | |||
058d3a00cf | |||
edb22966ff |
Binary file not shown.
Binary file not shown.
156
McuLib/m/appWrap.m
Normal file
156
McuLib/m/appWrap.m
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
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
|
@ -39,7 +39,7 @@ classdef asynchManage < handle
|
|||||||
methods (Access = private)
|
methods (Access = private)
|
||||||
function saveCallback(obj)
|
function saveCallback(obj)
|
||||||
try
|
try
|
||||||
mcuMask.saveAndClose(obj.maskBlockPath);
|
mcuMask.close(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.saveAndClose(obj.maskBlockPath);
|
mcuMask.close(obj.maskBlockPath);
|
||||||
mexing(0);
|
mexing(0);
|
||||||
catch ME
|
catch ME
|
||||||
warning('progr:Nneg', 'Ошибка при обновлении модели: %s', ME.message);
|
warning('progr:Nneg', 'Ошибка при обновлении модели: %s', ME.message);
|
||||||
|
@ -26,10 +26,11 @@ classdef compiler
|
|||||||
% Список заголовочных файлов (.h)
|
% Список заголовочных файлов (.h)
|
||||||
includes = { '.\'
|
includes = { '.\'
|
||||||
};
|
};
|
||||||
periphPath = mcuPath.get('wrapperPath');
|
wrapperPath = mcuPath.get('wrapperPath');
|
||||||
|
% [wrapperPath, ~, ~] = fileparts(wrapperPath);
|
||||||
% Формируем строки
|
% Формируем строки
|
||||||
wrapperSrcText = compiler.createSourcesBat('code_WRAPPER', sources, periphPath);
|
wrapperSrcText = compiler.createSourcesBat('code_WRAPPER', sources, wrapperPath);
|
||||||
wrapperIncText = compiler.createIncludesBat('includes_WRAPPER', includes, periphPath);
|
wrapperIncText = compiler.createIncludesBat('includes_WRAPPER', includes, wrapperPath);
|
||||||
|
|
||||||
% Записываем результат
|
% Записываем результат
|
||||||
res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: WRAPPER BAT'); % Всё прошло успешно
|
res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: WRAPPER BAT'); % Всё прошло успешно
|
||||||
@ -54,7 +55,7 @@ classdef compiler
|
|||||||
% Записываем результат
|
% Записываем результат
|
||||||
res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: APP WRAPPER BAT'); % Всё прошло успешно
|
res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: APP WRAPPER BAT'); % Всё прошло успешно
|
||||||
|
|
||||||
|
periphConfig.updatePeriphRunMexBat();
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,13 +8,15 @@ 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
|
% инициализация колонок если они пустые
|
||||||
% for i = 1:nCols
|
% такое случается при removeParameter
|
||||||
% tableControl.removeColumn(1);
|
if isempty(tableControl.Columns) || (nCols > 1)
|
||||||
% end
|
for i = 1:nCols
|
||||||
% end
|
tableControl.removeColumn(1);
|
||||||
% column = tableControl.addColumn(Name='Title', Type='edit');
|
end
|
||||||
% tableControl.Sortable = 'on';
|
column = tableControl.addColumn(Name='Title', Type='edit');
|
||||||
|
tableControl.Sortable = 'on';
|
||||||
|
end
|
||||||
column.Name = tableParameter.Alias;
|
column.Name = tableParameter.Alias;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
72
McuLib/m/mainWrap.m
Normal file
72
McuLib/m/mainWrap.m
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
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
|
@ -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,148 +58,37 @@ 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)
|
||||||
block = gcb;
|
appWrap.appWrapperFunc();
|
||||||
% Получаем имя функции и путь к файлам
|
|
||||||
[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)
|
||||||
block = gcb;
|
appWrap.saveAppWrapperCode();
|
||||||
|
|
||||||
% Получаем имя функции и путь к файлам
|
|
||||||
[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)
|
||||||
block = gcb;
|
appWrap.openAppWrapperCode();
|
||||||
|
|
||||||
% Получаем имя функции и путь к файлам
|
|
||||||
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
|
||||||
@ -220,36 +109,23 @@ 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();
|
||||||
@ -282,88 +158,30 @@ 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 saveAndClose(blockPath)
|
function updateModel()
|
||||||
|
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);
|
||||||
@ -482,9 +300,13 @@ classdef mcuMask
|
|||||||
out = sprintf(varargin{:});
|
out = sprintf(varargin{:});
|
||||||
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()
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
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)
|
||||||
% Открываем проводник для выбора файлов
|
% Открываем проводник для выбора файлов
|
||||||
[files, pathstr] = uigetfile({ ...
|
[files, pathstr] = uigetfile({ ...
|
||||||
@ -61,6 +61,7 @@ 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;
|
||||||
@ -91,6 +92,8 @@ classdef mcuPath
|
|||||||
param.Value = rel;
|
param.Value = rel;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
%% GET PATH STRING
|
||||||
|
|
||||||
function absPath = getAbsolutePath(relPath)
|
function absPath = getAbsolutePath(relPath)
|
||||||
% relativeToAbsolutePath — преобразует относительный путь в абсолютный.
|
% relativeToAbsolutePath — преобразует относительный путь в абсолютный.
|
||||||
%
|
%
|
||||||
@ -115,8 +118,6 @@ classdef mcuPath
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function rel = absoluteToRelativePath(pathstr)
|
function rel = absoluteToRelativePath(pathstr)
|
||||||
% absoluteToRelativePath — преобразует абсолютный путь в относительный от текущей директории.
|
% absoluteToRelativePath — преобразует абсолютный путь в относительный от текущей директории.
|
||||||
%
|
%
|
||||||
@ -163,6 +164,5 @@ classdef mcuPath
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -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.update(blockPath, config);
|
periphConfig.updateMask(blockPath, config);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -202,6 +202,8 @@ 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
|
||||||
@ -230,7 +232,15 @@ function definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, val_
|
|||||||
end
|
end
|
||||||
|
|
||||||
% Берём alias из маски
|
% Берём 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
|
if val_define ~= 0
|
||||||
% Значение параметра
|
% Значение параметра
|
||||||
@ -240,14 +250,16 @@ function definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, val_
|
|||||||
val = num2str(val); % Преобразуем результат в строку
|
val = num2str(val); % Преобразуем результат в строку
|
||||||
end
|
end
|
||||||
% Формируем define с кавычками и значением
|
% Формируем define с кавычками и значением
|
||||||
newDefine = ['-D"' alias '__EQ__' val '"'];
|
newDefine = ['-D"' def_name '__EQ__' val '"'];
|
||||||
else
|
elseif ~strcmp(param.Type, 'popup')
|
||||||
if mcuMask.read_checkbox(paramName)
|
if mcuMask.read_checkbox(paramName)
|
||||||
% Формируем define с кавычками без значения
|
% Формируем define с кавычками без значения
|
||||||
newDefine = ['-D"' alias '"'];
|
newDefine = ['-D"' def_name '"'];
|
||||||
else
|
else
|
||||||
newDefine = '';
|
newDefine = '';
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
newDefine = ['-D"' def_name '"'];
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,82 +1,215 @@
|
|||||||
classdef periphConfig
|
classdef periphConfig
|
||||||
|
|
||||||
methods(Static)
|
methods(Static)
|
||||||
function update(blockPath, config)
|
function updateMask(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
|
||||||
containerName = 'configTabAll';
|
rowWidth = str2double(get_param(blockPath, 'rowWidth'));
|
||||||
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')
|
containerName = 'configTabAll';
|
||||||
res = periphConfig.addCodeConfig(config.Code, periphPath);
|
periphConfig.clear_all_from_container(mask, containerName);
|
||||||
if res == 0
|
|
||||||
error('Ошибка: неудачное добавление кода периферии. Проверьте корректность файлов и путей в конфигурационном файле')
|
% Ищем контейнер, в который будем добавлять вкладки
|
||||||
end
|
container = mask.getDialogControl(containerName);
|
||||||
else
|
if isempty(container)
|
||||||
error('Ошибка: в конфигурационном файле не задан исходный код для симуляции периферии')
|
error('Контейнер "%s" не найден в маске.', containerName);
|
||||||
end
|
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);
|
tabCtrl = container.addDialogControl('tab', periph);
|
||||||
if res == 0
|
tabCtrl.Prompt = [periph ' Config'];
|
||||||
error('Ошибка: неудачное добавление функций для симуляции. Проверьте корректность названий функций в конфигурационном файле')
|
|
||||||
end
|
rowCountMap = containers.Map();
|
||||||
else
|
for j = 1:numel(defNames)
|
||||||
error('Ошибка: в конфигурационном файле не заданы функции для симуляции периферии')
|
defPrompt = defNames{j};
|
||||||
end
|
def = defines.(defPrompt);
|
||||||
|
|
||||||
% Проходим по каждому модулю (ADC, TIM...)
|
% Вызов функции добавления одного параметра
|
||||||
periphs = fieldnames(config);
|
periphConfig.addConfig(mask, containerName, periph, defPrompt, def, rowCountMap, rowWidth);
|
||||||
for i = 1:numel(periphs)
|
end
|
||||||
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.addDefineConfig(mask, containerName, periph, defPrompt, def);
|
|
||||||
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;
|
||||||
@ -167,19 +300,231 @@ classdef periphConfig
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
methods(Static, Access=private)
|
methods(Static, Access=private)
|
||||||
|
|
||||||
function res = addCodeConfig(codeConfig, periphPath)
|
function clear_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.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.Options, periphPath);
|
srcText = compiler.createSourcesBat('code_PERIPH', codeConfig.Sources, codePath);
|
||||||
incText = compiler.createIncludesBat('includes_PERIPH', codeConfig.Includes.Options, periphPath);
|
incText = compiler.createIncludesBat('includes_PERIPH', codeConfig.Includes, codePath);
|
||||||
|
|
||||||
% Записываем результат
|
% Записываем результат
|
||||||
res = compiler.updateRunMexBat(srcText, incText, ':: PERIPH BAT'); % Всё прошло успешно
|
res = compiler.updateRunMexBat(srcText, incText, ':: PERIPH BAT'); % Всё прошло успешно
|
||||||
@ -189,8 +534,8 @@ classdef periphConfig
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function res = addUserFunctions(userCodeConfig)
|
||||||
function res = addUserCodeConfig(userCodeConfig)
|
% Добавить функции и дефайны в исходный код wrapper
|
||||||
% userCodeConfig — структура config.UserCode
|
% userCodeConfig — структура config.UserCode
|
||||||
|
|
||||||
initFuncsText = '';
|
initFuncsText = '';
|
||||||
@ -200,27 +545,26 @@ classdef periphConfig
|
|||||||
if isfield(userCodeConfig, 'Functions')
|
if isfield(userCodeConfig, 'Functions')
|
||||||
funcs = userCodeConfig.Functions;
|
funcs = userCodeConfig.Functions;
|
||||||
|
|
||||||
if isfield(funcs, 'PeriphInit') && isfield(funcs.PeriphInit, 'Options')
|
if isfield(funcs, 'PeriphInit')
|
||||||
initFuncs = funcs.PeriphInit.Options;
|
initFuncs = funcs.PeriphInit;
|
||||||
initFuncsText = strjoin(strcat('\t', initFuncs, ';'), '\n');
|
initFuncsText = strjoin(strcat('\t', initFuncs, ';'), '\n');
|
||||||
end
|
end
|
||||||
|
|
||||||
if isfield(funcs, 'PeriphSimulation') && isfield(funcs.PeriphSimulation, 'Options')
|
if isfield(funcs, 'PeriphSimulation')
|
||||||
simFuncs = funcs.PeriphSimulation.Options;
|
simFuncs = funcs.PeriphSimulation;
|
||||||
simFuncsText = strjoin(strcat('\t', simFuncs, ';'), '\n');
|
simFuncsText = strjoin(strcat('\t', simFuncs, ';'), '\n');
|
||||||
end
|
end
|
||||||
|
|
||||||
if isfield(funcs, 'PeriphDeinit') && isfield(funcs.PeriphDeinit, 'Options')
|
if isfield(funcs, 'PeriphDeinit')
|
||||||
deinitFuncs = funcs.PeriphDeinit.Options;
|
deinitFuncs = funcs.PeriphDeinit;
|
||||||
deinitFuncsText = strjoin(strcat('\t', deinitFuncs, ';'), '\n');
|
deinitFuncsText = strjoin(strcat('\t', deinitFuncs, ';'), '\n');
|
||||||
end
|
end
|
||||||
|
|
||||||
res = periphConfig.updateWrapperCode(initFuncsText, simFuncsText, deinitFuncsText);
|
res = periphConfig.writeWrapperCode(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_...
|
||||||
@ -249,17 +593,27 @@ classdef periphConfig
|
|||||||
error('Ошибка: неудачная запись в файл при записи файла: %s', ME.message);
|
error('Ошибка: неудачная запись в файл при записи файла: %s', ME.message);
|
||||||
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)
|
||||||
@ -336,36 +690,107 @@ classdef periphConfig
|
|||||||
param.DialogControl.Row = 'current';
|
param.DialogControl.Row = 'current';
|
||||||
end
|
end
|
||||||
|
|
||||||
if strcmp(paramType, 'popup')
|
if isfield(def, 'Def')
|
||||||
param.TypeOptions = def.Def;
|
if strcmp(paramType, 'popup')
|
||||||
else
|
param.TypeOptions = def.Def;
|
||||||
param.Alias = def.Def;
|
else
|
||||||
|
param.Alias = def.Def;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
callback = sprintf('periphConfig.periphParamCallback("%s");', paramName);
|
||||||
|
param.Callback = callback;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function clear_all_from_container(mask, containerName)
|
|
||||||
% allControls = mask.getDialogControls();
|
%% ELEMENTARY
|
||||||
container = mask.getDialogControl(containerName);
|
|
||||||
if isempty(container)
|
|
||||||
warning('Контейнер "%s" не найден.', containerName);
|
|
||||||
return;
|
|
||||||
end
|
|
||||||
|
|
||||||
% Рекурсивно собрать все параметры (не вкладки)
|
function clear_single_periph_code_param(mask, periph)
|
||||||
paramsToDelete = mcuMask.collect_all_parameters(container);
|
% Очистка кода одного поля конфига
|
||||||
|
paramNames = {
|
||||||
|
['Hidden_' periph '_Sources'],
|
||||||
|
['Hidden_' periph '_Includes']
|
||||||
|
};
|
||||||
|
|
||||||
% Удаляем все параметры
|
for i = 1:numel(paramNames)
|
||||||
for i = 1:numel(paramsToDelete)
|
paramName = paramNames{i};
|
||||||
try
|
try
|
||||||
mask.removeParameter(paramsToDelete{i});
|
param = mask.getParameter(paramName);
|
||||||
|
param.Value = '';
|
||||||
catch
|
catch
|
||||||
warning('Не удалось удалить параметр %s', paramsToDelete{i});
|
% Параметр не существует — ничего не делаем
|
||||||
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
% Рекурсивно удалить все вкладки внутри контейнера
|
% Сохраняем Includes, если они есть
|
||||||
mcuMask.delete_all_tabs(mask, container);
|
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
|
||||||
|
% warning('Неподдерживаемый тип данных: сохранено как пустая строка');
|
||||||
|
value = '';
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function res = ternary(cond, valTrue, valFalse)
|
function res = ternary(cond, valTrue, valFalse)
|
||||||
|
@ -30,15 +30,17 @@ set defines_WRAPPER=-D"MATLAB"^ -D"__sizeof_ptr=8"
|
|||||||
|
|
||||||
:: -------------------------WRAPPER PATHS AND CODE---------------------------
|
:: -------------------------WRAPPER PATHS AND CODE---------------------------
|
||||||
:: оболочка, которая будет моделировать работу МК в симулинке
|
:: оболочка, которая будет моделировать работу МК в симулинке
|
||||||
set includes_WRAPPER=-I"."^
|
:: WRAPPER BAT START
|
||||||
-I".\MCU_Wrapper"^
|
|
||||||
-I".\app_wrapper"
|
:: WRAPPER BAT END
|
||||||
|
|
||||||
|
:: 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
|
||||||
|
|
||||||
|
@ -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="1721556499" 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="2658716694" 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>
|
||||||
|
Loading…
Reference in New Issue
Block a user