330 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Matlab
		
	
	
	
	
	
			
		
		
	
	
			330 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Matlab
		
	
	
	
	
	
% Компилирует 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
 | 
						||
% 
 |