classdef mcuMask % Главный класс управления маской блока Simulink для микроконтроллера % Содержит callback-функции и утилиты для работы с маской %% CALLBACKS - функции обратного вызова для элементов маски methods(Static) % Функция инициализации маски - вызывается при загрузке блока function MaskInitialization(maskInitContext) % Получаем хэндл текущего блока blk = gcbh; % Получаем объект маски текущего блока mask = Simulink.Mask.get(gcb); % Разрешаем самомодификацию маски и отключаем ссылки set_param(blk,"MaskSelfModifiable","on") set_param(blk, 'LinkStatus', 'none'); % Проверяем доступность findjobj для внешней консоли try findjobjAvailable = exist('findjobj', 'file') == 2; catch findjobjAvailable = false; end % Настраиваем параметры внешней консоли в зависимости от доступности findjobj checkboxParamName = 'extConsol'; findjobjLinkName = 'findjobj_link'; checkboxParam = mask.getParameter(checkboxParamName); findjobjLink = mask.getDialogControl(findjobjLinkName); if isempty(findjobjLink) error('Параметр %s не найден в маске.', findjobjLinkName); end if isempty(checkboxParam) error('Параметр %s не найден в маске.', checkboxParamName); end % Блокируем чекбокс если findjobj не найден if ~findjobjAvailable checkboxParam.Enabled = 'off'; checkboxParam.Value = 'off'; checkboxParam.Prompt = 'External Console (requires findjobj)'; findjobjLink.Visible = 'on'; % Показываем ссылку для скачивания else checkboxParam.Enabled = 'on'; checkboxParam.Prompt = 'External Console'; findjobjLink.Visible = 'off'; % Скрываем ссылку end % Форматируем таблицы исходных файлов и инклюдов table_names = {'srcTable', 'incTable'}; for k = 1:numel(table_names) table_name = table_names{k}; customtable.format(table_name); end % Устанавливаем описание блока textDesc = ['Блок для настройки параметров симуляции микроконтроллера. ' newline ... 'Позволяет задавать параметры оболочки, приложения МК и периферии']; toolTextArea = mask.getDialogControl('BlockDesc'); toolTextArea.Prompt = textDesc; end %% WRAPPER PARAMS - callback-функции для параметров обёртки function wrapperPath_add(callbackContext) % Добавление пути к файлам обёртки mcuPath.addPath('wrapperPath'); end function enableThreading(callbackContext) % Включение/выключение многопоточности mainWrap.enableThreading(); end function enableDeinit(callbackContext) % Включение/выключение деинициализации mainWrap.enableDeinit(); end function extConsol(callbackContext) % Управление внешней консолью mainWrap.extConsol(); end %% USER WRAPPER CODE - callback-функции для пользовательского кода function appWrapperPath_add(callbackContext) % Добавление пути к файлам обёртки приложения mcuPath.addPath('appWrapperPath'); end function appWrapperFunc(callbackContext) % Загрузка функции обёртки для редактирования appWrap.appWrapperFunc(); end function saveAppWrapperCode(callbackContext) % Сохранение отредактированного кода обёртки appWrap.saveAppWrapperCode(); end function openAppWrapperCode(callbackContext) % Открытие кода обёртки во внешнем редакторе appWrap.openAppWrapperCode(); end %% USER CODE - callback-функции для пользовательского кода function srcTable(callbackContext) % Обновление таблицы исходных файлов customtable.update('srcTable'); end function incTable(callbackContext) % Обновление таблицы заголовочных файлов customtable.update('incTable'); end function btnAddSrc(callbackContext) % Добавление исходных файлов через диалог выбора mcuPath.addSourceFileTable('srcTable', 'Выберите исходные файлы'); end function btnAddInc(callbackContext) % Добавление путей включения через диалог выбора mcuPath.addPathTable('incTable', 'Выберите папку с заголовочными файлами'); end %% PERIPH CONFIG - callback-функции для конфигурации периферии function periphPath_add(callbackContext) % Добавление пути к конфигурационному файлу периферии mcuPath.addAnyFile('periphPath'); end function periphUpdate(callbackContext) % Обновление конфигурации периферии с асинхронным управлением modelName = bdroot(gcb); blockName = gcb; mgr = asynchManage(modelName, blockName); mgr.updateGUIfromConfig(); % Запуск обновления через таймер end %% COMPILE - callback-функции для компиляции function compile(callbackContext) % Компиляция S-функции compiler.compile(); end function setSFuncName(callbackContext) % Установка имени S-функции в исходном коде block = gcb; newName = mcuMask.get_name(); % Путь к файлу MCU.c cFilePath = fullfile(pwd, mcuPath.get('wrapperPath'), 'MCU.c'); % Чтение файла try fileText = fileread(cFilePath); catch return; end % Поиск и замена определения имени S-функции pattern = '#define\s+S_FUNCTION_NAME\s+\w+'; newLine = ['#define S_FUNCTION_NAME ', newName]; updatedText = regexprep(fileText, pattern, newLine); % Запись изменений обратно в файл fid = fopen(cFilePath, 'w', 'n', 'UTF-8'); if fid == -1 error('Не удалось открыть файл для записи.'); end fwrite(fid, updatedText); fclose(fid); end %% LINK TO EXTERNAL CONSOLE - callback для внешней консоли function findjobj_link(callbackContext) % Открытие ссылки на утилиту findjobj web('https://www.mathworks.com/matlabcentral/fileexchange/14317-findjobj-find-java-handles-of-matlab-graphic-objects'); end end %% GENERAL TOOLS - общие утилиты для работы с маской methods(Static, Access = public) function updateModel() % Обновление модели с компиляцией S-функции addpath(mcuPath.get('wrapperPath')); res = mexing(1); if res ~= 0 return; end end function close(blockPath) % Закрытие маски с сохранением параметров try modelName = bdroot(blockPath); set_param(blockPath, 'MaskSelfModifiable', 'on'); % Применяем текущие значения маски currentMaskValues = get_param(blockPath, 'MaskValues'); set_param(blockPath, 'MaskValues', currentMaskValues); save_system(modelName); catch ME warning('progr:Nneg', 'Ошибка при сохранении маски: %s', ME.message); end close_system(blockPath, 0); end function open(blockPath, clear_flag) % Открытие маски блока open_system(blockPath, 'mask'); mcuMask.disp(clear_flag, ''); end function name = get_name() % Получение имени S-функции из параметра маски block = gcb; name = get_param(block, 'sfuncName'); end function checkbox_state = read_checkbox(checkboxName) % Чтение состояния чекбокса из параметров маски maskValues = get_param(gcbh, 'MaskValues'); paramNames = get_param(gcbh, 'MaskNames'); inxCheckBox = find(strcmp(paramNames, checkboxName)); checkbox_state_str = maskValues{inxCheckBox}; if strcmpi(checkbox_state_str, 'on') checkbox_state = 1; else checkbox_state = 0; end end function children = get_children(ctrl) % Получение дочерних элементов управления маски if isprop(ctrl, 'DialogControls') children = ctrl.DialogControls; elseif isprop(ctrl, 'Controls') children = ctrl.Controls; elseif isprop(ctrl, 'Children') children = ctrl.Children; else children = []; end end function params = collect_all_parameters(container) % Рекурсивный сбор всех параметров маски params = {}; children = container.DialogControls; for i = 1:numel(children) ctrl = children(i); if isa(ctrl, 'Simulink.dialog.Tab') % Рекурсивный обход вкладок params = [params, mcuMask.collect_all_parameters(ctrl)]; else % Добавление имени параметра params{end+1} = ctrl.Name; end end end function delete_all_tabs(mask, container) % Рекурсивное удаление всех вкладок маски children = container.DialogControls; for i = numel(children):-1:1 ctrl = children(i); if isa(ctrl, 'Simulink.dialog.Tab') % Рекурсивное удаление вложенных вкладок mcuMask.delete_all_tabs(mask, ctrl); try container.removeDialogControl(ctrl.Name); catch ME warning('Не удалось удалить вкладку %s: %s', ctrl.Name, ME.message); end end end end function tool(text, example) % Установка текста подсказки и примера в элементы маски block = gcb; mask = Simulink.Mask.get(block); toolTextArea = mask.getDialogControl('toolText'); exampleTextArea = mask.getDialogControl('exampleText'); toolTextArea.Prompt = text; exampleTextArea.Prompt = example; end function disp(clcFlag, varargin) % Вывод текста в консоль маски if clcFlag set_param(gcb, 'consoleOutput', ''); end if length(varargin) == 1 && ischar(varargin{1}) out = varargin{1}; else out = sprintf(varargin{:}); end out_now = get_param(gcb, 'consoleOutput'); if ~strcmp(out, '') && ~strcmp(out_now, '') set_param(gcb, 'consoleOutput', [out_now newline out]); else set_param(gcb, 'consoleOutput', [out_now out]); end end function updateModelAsync() % Асинхронное обновление модели через таймер mdl = bdroot(gcb); try set_param(mdl, 'ApplyChanges', 'on'); catch beep end t = timer('StartDelay', 0.01, 'TimerFcn', @(~,~) set_param(mdl, 'SimulationCommand', 'update')); start(t); end function v = getMyLibVersion() % Получение версии библиотеки v = 'pre-1.04'; end end end