classdef mcuMask %% CALLBACKS methods(Static) % Following properties of 'maskInitContext' are avalaible to use: % - BlockHandle % - MaskObject % - MaskWorkspace - Use get/set APIs to work with mask workspace. function MaskInitialization(maskInitContext) % Получаем хэндл текущего блока blk = gcbh; % Получаем объект маски текущего блока mask = Simulink.Mask.get(gcb); set_param(blk,"MaskSelfModifiable","on") set_param(blk, 'LinkStatus', 'none'); % mcuMask.disp(1,''); try % Проверка наличия findjobj findjobjAvailable = exist('findjobj', 'file') == 2; catch findjobjAvailable = false; end % Имя checkbox-параметра (укажите точное имя из маски) 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 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 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 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 function periphPath_add(callbackContext) mcuPath.addAnyFile('periphPath'); end function periphUpdate(callbackContext) modelName = bdroot(gcb); % получить имя верхнего уровня модели blockName = gcb; mgr = asynchManage(modelName, blockName); % создать объект класса mgr.updateGUIfromConfig(); % запустить сохранение и обновление end %% COMPILE function compile(callbackContext) compiler.compile(); end function setSFuncName(callbackContext) block = gcb; % Получаем параметр имени S-Function из маски блока newName = mcuMask.get_name(); % Путь к файлу, в котором надо заменить строку cFilePath = fullfile(pwd, mcuPath.get('wrapperPath'), 'MCU.c'); % <-- укажи правильный путь % Считаем файл в память try fileText = fileread(cFilePath); catch return; end % Регулярное выражение для поиска строки с define % Заменим строку вида: #define S_FUNCTION_NAME old_name 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 function findjobj_link(callbackContext) 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() 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 % Считываем текущее имя модели 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() block = gcb; % Получаем параметр имени S-Function из маски блока 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; %#ok 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) % Устанавливает заданный текст в параметр Text Area 'toolText' через объект маски % Получаем ссылку на текущий блок 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 end end