% Компилирует S-function clear, clc close; Ts = 0.00001; delete("*.mexw64") delete("*.mexw64.pdb") delete(".\MCU_Wrapper\Outputs\*.*"); % Флаг режима отладки definesArg = buildDefinesString(); definesUserArg = parseDefinesMaskText(); definesAllArg = [definesArg + " " + definesUserArg]; maskValues = get_param(gcbh, 'MaskValues'); paramNames = get_param(gcbh, 'MaskNames'); inxDebug = find(strcmp(paramNames, 'enableDebug')); idxExtConsole = find(strcmp(paramNames, 'extConsol')); idxFullOutput = find(strcmp(paramNames, 'fullOutput')); isDebug = maskValues{inxDebug}; isExtConsole = maskValues{idxExtConsole}; isFullOutput = maskValues{idxFullOutput}; if strcmpi(isDebug, 'on') modeArg = "debug"; else modeArg = "release"; end if strcmpi(isFullOutput, 'on') echoArg = 'echo_enable'; else echoArg = 'echo_disable'; end [includesArg, codeArg] = make_mex_arguments('incTable', 'srcTable'); set_param(gcb, 'consoleOutput', ''); % Вызов батника с двумя параметрами: includes и code cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" %s %s', includesArg, codeArg, definesAllArg, modeArg, echoArg); if(strcmpi(isExtConsole, 'on')) cmdout = runBatAndShowOutput(cmd); else [status, cmdout]= system(cmd); end % Сохраним вывод в параметр маски с именем 'consoleOutput' set_param(gcb, 'consoleOutput', cmdout); % % Обновим Mask Display для показа % maskDisplayStr = sprintf('disp(''%s'')', cmdout); % set_param(gcb, 'MaskDisplay', maskDisplayStr); beep %% function [includesArg, codeArg] = make_mex_arguments(incTableName, srcTableame) %MAKE_MEX_ARGUMENTS Формирует строки аргументов для вызова mex-компиляции через батник % % [includesArg, codeArg] = make_mex_arguments(includesCell, codeCell) % % Вход: % includesCell — ячейковый массив путей к директориям include % codeCell — ячейковый массив исходных файлов % % Выход: % includesArg — строка для передачи в батник, например: "-I"inc1" -I"inc2"" % codeArg — строка с исходниками, например: ""src1.c" "src2.cpp"" % Здесь пример получения из маски текущего блока (замени по своему) blockHandle = gcbh; % или замени на нужный блок includesCell = parseCellString(get_param(blockHandle, incTableName)); codeCell = parseCellString(get_param(blockHandle, srcTableame)); % Оборачиваем пути в кавычки и добавляем -I includesStr = strjoin(cellfun(@(f) ['-I"' f '"'], includesCell, 'UniformOutput', false), ' '); % Оборачиваем имена файлов в кавычки codeStr = strjoin(cellfun(@(f) ['"' f '"'], codeCell, 'UniformOutput', false), ' '); % Удаляем символ переноса строки и пробел в конце, если вдруг попал codeStr = strtrim(codeStr); includesStr = strtrim(includesStr); % Оборачиваем всю строку в кавычки, чтобы батник корректно понял % includesArg = ['"' includesStr '"']; % codeArg = ['"' codeStr '"']; includesArg = includesStr; codeArg = codeStr; end function cmdret = runBatAndShowOutput(cmd) import java.io.*; import java.lang.*; cmdEnglish = ['chcp 437 > nul && ' cmd]; pb = java.lang.ProcessBuilder({'cmd.exe', '/c', cmdEnglish}); pb.redirectErrorStream(true); process = pb.start(); reader = BufferedReader(InputStreamReader(process.getInputStream())); cmdret = ""; % Здесь будем накапливать весь вывод while true if reader.ready() line = char(reader.readLine()); if isempty(line) break; end cmdret = cmdret + string(line) + newline; % сохраняем вывод % Здесь выводим только новую строку safeLine = strrep(line, '''', ''''''); % Экранируем апострофы logWindow_append(safeLine); drawnow; % обновляем GUI else if ~process.isAlive() % дочитываем оставшиеся строки while reader.ready() line = char(reader.readLine()); if isempty(line) break; end cmdret = cmdret + string(line) + newline; % сохраняем вывод safeLine = strrep(line, '''', ''''''); logWindow_append(safeLine); drawnow; end break; end pause(0.2); end end process.waitFor(); end function logWindow_append(line) persistent fig hEdit jScrollPane jTextArea if isempty(fig) || ~isvalid(fig) fig = figure('Name', 'Log Window', 'Position', [100 100 600 400]); hEdit = uicontrol('Style', 'edit', ... 'Max', 2, 'Min', 0, ... 'Enable', 'on', ... % Включаем взаимодействие 'FontName', 'Courier New', ... 'Position', [10 10 580 380], ... 'HorizontalAlignment', 'left', ... 'BackgroundColor', 'white', ... 'Tag', 'LogWindowFigure'); jScrollPane = findjobj(hEdit); % JScrollPane jTextArea = jScrollPane.getViewport.getView; % JTextArea внутри JScrollPane end oldText = get(hEdit, 'String'); if ischar(oldText) oldText = {oldText}; end set(hEdit, 'String', [oldText; {line}]); drawnow; % Автоскролл вниз: jTextArea.setCaretPosition(jTextArea.getDocument.getLength); drawnow; end function definesArg = buildDefinesString() blockHandle = gcbh; % Получаем MaskValues и MaskNames maskValues = get_param(blockHandle, 'MaskValues'); paramNames = get_param(blockHandle, 'MaskNames'); % Индексы параметров idxThreading = find(strcmp(paramNames, 'enableThreading')); idxDeinit = find(strcmp(paramNames, 'enableDeinit')); idxCycles = find(strcmp(paramNames, 'threadCycles')); idxClk = find(strcmp(paramNames, 'mcuClk')); if any([isempty(idxThreading), isempty(idxDeinit),isempty(idxCycles), isempty(idxClk)]) error('Один или несколько параметров не найдены в маске'); end % Значения ThreadingVal = maskValues{idxThreading}; DeinitVal = maskValues{idxDeinit}; cyclesVal = maskValues{idxCycles}; clkMHz = str2double(maskValues{idxClk}); clkHz = round(clkMHz * 1e6); % Формируем defines в формате: -D"NAME=VALUE" if strcmpi(ThreadingVal, 'on') def1 = ['-D"RUN_APP_MAIN_FUNC_THREAD"']; else def1 = ['']; end if strcmpi(DeinitVal, 'on') def2 = ['-D"DEINITIALIZE_AFTER_SIM"']; else def2 = ['']; end def3 = ['-D"DEKSTOP_CYCLES_FOR_MCU_APP__EQ__' cyclesVal '"']; def4 = ['-D"MCU_CORE_CLOCK__EQ__' num2str(clkHz) '"']; definesArg = strjoin({def1, def2, def3, def4}, ' '); % definesArg = ['"' definesStr '']; % definesArg = definesStr; end function definesUserArg = parseDefinesMaskText() blockHandle = gcbh; % Получаем MaskValues и MaskNames maskValues = get_param(blockHandle, 'MaskValues'); paramNames = get_param(blockHandle, 'MaskNames'); % Индекс параметра userDefs idxUserDefs = find(strcmp(paramNames, 'userDefs')); definesText = maskValues{idxUserDefs}; % Текст с пользовательскими определениями % Убираем буквальные символы \n и \r definesText = strrep(definesText, '\n', ' '); definesText = strrep(definesText, '\r', ' '); % Разбиваем по переносам строк lines = split(definesText, {'\n', '\r\n', '\r'}); parts = strings(1,0); % пустой массив строк for k = 1:numel(lines) line = strtrim(lines{k}); if isempty(line) continue; end % Разбиваем по пробелам, чтобы получить отдельные определения в строке tokens = split(line); for t = 1:numel(tokens) token = strtrim(tokens{t}); if isempty(token) continue; end eqIdx = strfind(token, '='); if isempty(eqIdx) % Просто ключ без значения parts(end+1) = sprintf('-D"%s"', token); else key = strtrim(token(1:eqIdx(1)-1)); val = strtrim(token(eqIdx(1)+1:end)); parts(end+1) = sprintf('-D"%s__EQ__%s"', key, val); end end end definesUserArg = strjoin(parts, ' '); end function out = parseCellString(str) str = strtrim(str); if startsWith(str, '{') && endsWith(str, '}') str = str(2:end-1); end parts = split(str, ';'); out = cell(numel(parts), 1); for i = 1:numel(parts) el = strtrim(parts{i}); if startsWith(el, '''') && endsWith(el, '''') el = el(2:end-1); end out{i} = el; end if isempty(out) || (numel(out) == 1 && isempty(out{1})) out = {}; end end function str = cellArrayToString(cellArray) quoted = cellfun(@(s) ['''' s ''''], cellArray, 'UniformOutput', false); str = ['{' strjoin(quoted, ';') '}']; end % % Компилирует S-function % clear, clc, % % set = mex.getCompilerConfigurations('C', 'Selected'); % % Ts = 0.00001; % % delete("*.mexw64") % delete("*.mexw64.pdb") % delete(".\MCU_Wrapper\Outputs\*.*"); % % status=system('.\MCU_Wrapper\run_mex.bat debug'); % % if status==0 % beep % else % error('Error!'); % end %