diff --git a/config_reader.asv b/config_reader.asv index feeb816..bd9c938 100644 --- a/config_reader.asv +++ b/config_reader.asv @@ -8,45 +8,26 @@ load_system(model); % если модель ещё не загружена update_mask_from_config(block); disp('Маска обновлена по конфигу.'); - function update_mask_from_config(blockPath) config = load_periph_config(); mask = Simulink.Mask.get(blockPath); - tabPrompt = 'Config Peripheral'; % Название вкладки, как отображается в маске + tabPrompt = 'Config Peripheral'; % Имя вкладки (Prompt) - controls = mask.getDialogControls(); + allControls = mask.getDialogControls(); + tabCtrl = find_tab_by_prompt(allControls, tabPrompt); - % Выведем все контролы и их свойства для отладки - fprintf('Всего контролов: %d\n', numel(controls)); - for k = 1:numel(controls) - ctrl = controls(k); - props = properties(ctrl); - fprintf('Контрол #%d: Name="%s", Prompt="%s", Style="%s"\n', ... - k, ctrl.Name, ctrl.Prompt, ctrl.Style); + if isempty(tabCtrl) + error('Вкладка с названием "%s" не найдена в маске', tabPrompt); end - % Ищем вкладку по Prompt - tabIdx = find(arrayfun(@(c) strcmp(c.Style,'tab') && strcmp(c.Prompt, tabPrompt), controls), 1); - - if isempty(tabIdx) - error('Вкладка с названием "%s" не найдена.', tabPrompt); + % Удаляем все контролы внутри вкладки + children = tabCtrl.DialogControls; + while ~isempty(children) + tabCtrl.removeControl(children(1)); + children = tabCtrl.DialogControls; % обновляем список после удаления end - tabName = controls(tabIdx).Name; - fprintf('Найдена вкладка: Name="%s"\n', tabName); - - % Удаляем параметры из найденной вкладки - i = 1; - while i <= numel(mask.Parameters) - if strcmp(mask.Parameters(i).TabName, tabName) - mask.removeParameter(i); - else - i = i + 1; - end - end - - % Добавляем параметры в эту вкладку periphs = fieldnames(config); for i = 1:numel(periphs) periph = periphs{i}; @@ -54,35 +35,54 @@ function update_mask_from_config(blockPath) defNames = fieldnames(defines); for j = 1:numel(defNames) - defName = defNames{j}; - def = defines.(defName); + defPrompt = defNames{j}; + def = defines.(defPrompt); + + % Обрабатываем только checkbox и edit + switch lower(def.Type) + case 'checkbox' + paramType = 'checkbox'; + case 'edit' + paramType = 'edit'; + otherwise + continue; + end + + paramName = matlab.lang.makeValidName([periph '_' defPrompt]); val = def.Default; if islogical(val) - valStr = mat2str(val); + if val + valStr = 'on'; + else + valStr = 'off'; + end elseif isnumeric(val) valStr = num2str(val); elseif ischar(val) - valStr = ['''' val '''']; + valStr = val; else - error('Unsupported default value type for %s.%s', periph, defName); + error('Unsupported default value type for %s.%s', periph, defPrompt); end - mask.addParameter( ... - 'Type', def.Type, ... - 'Prompt', [periph ' - ' defName], ... - 'Name', [periph '_' defName], ... + + % Добавляем параметр в маску (без TabName) + mask.addParameter(... + 'Type', paramType, ... + 'Prompt', defPrompt, ... + 'Name', paramName, ... 'Value', valStr, ... - 'TabName', tabName ... - ); + 'Container', tabPrompt); + + disp(['paramType = ', paramType]); + disp(['paramName = ', paramName]); end end end -function config = load_periph_config() - jsonText = fileread('periph_config.json'); - config = jsondecode(jsonText); -end + + + function config = load_periph_config() @@ -119,3 +119,41 @@ function clear_params_from_tab(blockPath, tabPrompt) end end + +%% поиск вкладки +function tab = find_tab_by_name(controls, targetName) + tab = []; + + for i = 1:numel(controls) + ctrl = controls(i); + + % Проверяем, вкладка ли это и совпадает ли имя + if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName) + tab = ctrl; + return; + end + + % Если это контейнер — обходим его детей + children = get_children(ctrl); + if ~isempty(children) + tab = find_tab_by_name(children, targetName); + if ~isempty(tab) + return; + end + end + 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 + diff --git a/config_reader.m b/config_reader.m index 08bc06c..713783e 100644 --- a/config_reader.m +++ b/config_reader.m @@ -8,44 +8,26 @@ load_system(model); % если модель ещё не загружена update_mask_from_config(block); disp('Маска обновлена по конфигу.'); - function update_mask_from_config(blockPath) config = load_periph_config(); mask = Simulink.Mask.get(blockPath); - tabPrompt = 'Config Peripheral'; % Название вкладки, как отображается в маске + tabName = 'configTab'; % Имя вкладки (Prompt) - controls = mask.getDialogControls(); - - allTabs = find_all_tabs(mask); - - fprintf('Найдено вкладок: %d\n', numel(allTabs)); - for i = 1:numel(allTabs) - fprintf('Tab %d: Name="%s", Prompt="%s"\n', i, allTabs(i).Name, allTabs(i).Prompt); + allControls = mask.getDialogControls(); + tabCtrl = find_tab_by_name(allControls, tabName); + + if isempty(tabCtrl) + error('Вкладка с названием "%s" не найдена в маске', tabName); end - - % Ищем вкладку по Prompt - tabIdx = find(arrayfun(@(c) strcmp(c.Style,'tab') && strcmp(c.Prompt, tabPrompt), controls), 1); - - if isempty(tabIdx) - error('Вкладка с названием "%s" не найдена.', tabPrompt); + % Удаляем все контролы внутри вкладки + children = tabCtrl.DialogControls; + while ~isempty(children) + mask.removeParameter(children(1).Name); + children = tabCtrl.DialogControls; % обновляем список после удаления end - tabName = controls(tabIdx).Name; - fprintf('Найдена вкладка: Name="%s"\n', tabName); - - % Удаляем параметры из найденной вкладки - i = 1; - while i <= numel(mask.Parameters) - if strcmp(mask.Parameters(i).TabName, tabName) - mask.removeParameter(i); - else - i = i + 1; - end - end - - % Добавляем параметры в эту вкладку periphs = fieldnames(config); for i = 1:numel(periphs) periph = periphs{i}; @@ -53,62 +35,51 @@ function update_mask_from_config(blockPath) defNames = fieldnames(defines); for j = 1:numel(defNames) - defName = defNames{j}; - def = defines.(defName); + defPrompt = defNames{j}; + def = defines.(defPrompt); + + % Обрабатываем только checkbox и edit + switch lower(def.Type) + case 'checkbox' + paramType = 'checkbox'; + case 'edit' + paramType = 'edit'; + otherwise + continue; + end + + paramName = matlab.lang.makeValidName([periph '_' defPrompt]); val = def.Default; if islogical(val) - valStr = mat2str(val); + if val + valStr = 'on'; + else + valStr = 'off'; + end elseif isnumeric(val) valStr = num2str(val); elseif ischar(val) - valStr = ['''' val '''']; + valStr = val; else - error('Unsupported default value type for %s.%s', periph, defName); + error('Unsupported default value type for %s.%s', periph, defPrompt); end - mask.addParameter( ... - 'Type', def.Type, ... - 'Prompt', [periph ' - ' defName], ... - 'Name', [periph '_' defName], ... + + % Добавляем параметр в маску (без TabName) + mask.addParameter(... + 'Type', paramType, ... + 'Prompt', defPrompt, ... + 'Name', paramName, ... 'Value', valStr, ... - 'TabName', tabName ... - ); + 'Container', tabName); end end end -function tabs = find_all_tabs(mask) - controls = mask.getDialogControls(); - tabs = find_tabs_recursive(controls); -end -function tabs = find_tabs_recursive(controls) - tabs = []; - for i = 1:numel(controls) - ctrl = controls(i); - % Проверяем тип контролла (у разных версий API может отличаться) - % Чтобы не упасть, проверяем, есть ли поле Type - if isprop(ctrl, 'Type') - if strcmp(ctrl.Type, 'tab') - tabs = [tabs, ctrl]; %#ok - elseif any(strcmp(ctrl.Type, {'tabcontainer', 'group', 'panel'})) - % В этих контролах могут быть свои Controls или Children - if isprop(ctrl, 'Controls') - subtabs = find_tabs_recursive(ctrl.Controls); - elseif isprop(ctrl, 'Children') - subtabs = find_tabs_recursive(ctrl.Children); - else - subtabs = []; - end - tabs = [tabs, subtabs]; %#ok - end - else - % Если у контролла нет свойства Type - игнорируем - end - end -end + function config = load_periph_config() @@ -117,21 +88,21 @@ function config = load_periph_config() end -function clear_params_from_tab(blockPath, tabPrompt) +function clear_params_from_tab(blockPath, tabName) mask = Simulink.Mask.get(blockPath); controls = mask.getDialogControls; tabs = controls(strcmp({controls.Type}, 'tab')); tabName = ''; for i = 1:numel(tabs) - if strcmp(tabs(i).Prompt, tabPrompt) + if strcmp(tabs(i).Prompt, tabName) tabName = tabs(i).Name; % внутреннее имя вкладки break; end end if isempty(tabName) - error('Вкладка с названием "%s" не найдена.', tabPrompt); + error('Вкладка с названием "%s" не найдена.', tabName); end % Удаляем параметры с TabName == tabName @@ -145,3 +116,41 @@ function clear_params_from_tab(blockPath, tabPrompt) end end + +%% поиск вкладки +function tab = find_tab_by_name(controls, targetName) + tab = []; + + for i = 1:numel(controls) + ctrl = controls(i); + + % Проверяем, вкладка ли это и совпадает ли имя + if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName) + tab = ctrl; + return; + end + + % Если это контейнер — обходим его детей + children = get_children(ctrl); + if ~isempty(children) + tab = find_tab_by_name(children, targetName); + if ~isempty(tab) + return; + end + end + 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 + diff --git a/matlab.mat b/matlab.mat deleted file mode 100644 index cadce09..0000000 Binary files a/matlab.mat and /dev/null differ diff --git a/mcu_test_r2023.slx b/mcu_test_r2023.slx index da4b025..898e9d4 100644 Binary files a/mcu_test_r2023.slx and b/mcu_test_r2023.slx differ diff --git a/mexing.asv b/mexing.asv new file mode 100644 index 0000000..5220da6 --- /dev/null +++ b/mexing.asv @@ -0,0 +1,305 @@ +% Компилирует S-function +clear, clc +close; + + +Ts = 0.00001; + +delete("*.mexw64") +delete("*.mexw64.pdb") +delete(".\MCU_Wrapper\Outputs\*.*"); +set_param(gcb, 'consoleOutput', ''); + +% Флаг режима отладки +definesArg = buildWrapperDefinesString(); +definesUserArg = parseDefinesMaskText(); +definesAllArg = [definesArg + " " + definesUserArg]; + + +if read_checkbox('enableDebug') + modeArg = "debug"; +else + modeArg = "release"; +end + +if read_checkbox('fullOutput') || read_checkbox('extConsol') + echoArg = 'echo_enable'; +else + echoArg = 'echo_disable'; + +end + +[includesArg, codeArg] = make_mex_arguments('incTable', 'srcTable'); + +% Вызов батника с двумя параметрами: includes и code +cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" %s %s', includesArg, codeArg, definesAllArg, modeArg, echoArg); + + + +if read_checkbox('extConsol') + 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 + + + +%% DEFINE PARAMS + + +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 definesWrapperArg = buildWrapperDefinesString() + blockHandle = gcbh; + + % Получаем MaskValues и MaskNames + maskValues = get_param(blockHandle, 'MaskValues'); + paramNames = get_param(blockHandle, 'MaskNames'); + + % Индексы параметров + idxCycles = find(strcmp(paramNames, 'threadCycles')); + idxClk = find(strcmp(paramNames, 'mcuClk')); + + % Значения + cyclesVal = maskValues{idxCycles}; + clkMHz = str2double(maskValues{idxClk}); + clkHz = round(clkMHz * 1e6); + + % Формируем defines в формате: -D"NAME=VALUE" + if read_checkbox('enableThreading') + def1 = ['-D"RUN_APP_MAIN_FUNC_THREAD"']; + else + def1 = ['']; + end + + if read_checkbox('enableDeinit') + 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}, ' '); +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 + + +%% PARSE FUNCTIONS + +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 + + + +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 + + +%% CONSOLE FUNCTIONS + +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 diff --git a/mexing.m b/mexing.m index 1775a9a..6a99822 100644 --- a/mexing.m +++ b/mexing.m @@ -8,30 +8,21 @@ Ts = 0.00001; delete("*.mexw64") delete("*.mexw64.pdb") delete(".\MCU_Wrapper\Outputs\*.*"); +set_param(gcb, 'consoleOutput', ''); % Флаг режима отладки -definesArg = buildDefinesString(); +definesWrapperArg = buildWrapperDefinesString(); definesUserArg = parseDefinesMaskText(); -definesAllArg = [definesArg + " " + definesUserArg]; +definesAllArg = [definesWrapperArg + " " + 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') +if read_checkbox('enableDebug') modeArg = "debug"; else modeArg = "release"; end -if strcmpi(isFullOutput, 'on') +if read_checkbox('fullOutput') || read_checkbox('extConsol') echoArg = 'echo_enable'; else echoArg = 'echo_disable'; @@ -40,13 +31,12 @@ 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')) +if read_checkbox('extConsol') cmdout = runBatAndShowOutput(cmd); else [status, cmdout]= system(cmd); @@ -63,7 +53,7 @@ beep -%% +%% DEFINE PARAMS function [includesArg, codeArg] = make_mex_arguments(incTableName, srcTableame) @@ -104,84 +94,8 @@ function [includesArg, codeArg] = make_mex_arguments(incTableName, srcTableame) 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() +function definesWrapperArg = buildWrapperDefinesString() blockHandle = gcbh; % Получаем MaskValues и MaskNames @@ -189,30 +103,22 @@ function definesArg = buildDefinesString() 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') + if read_checkbox('enableThreading') def1 = ['-D"RUN_APP_MAIN_FUNC_THREAD"']; else def1 = ['']; end - if strcmpi(DeinitVal, 'on') + if read_checkbox('enableDeinit') def2 = ['-D"DEINITIALIZE_AFTER_SIM"']; else def2 = ['']; @@ -221,9 +127,7 @@ function definesArg = buildDefinesString() 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; + definesWrapperArg = strjoin({def1, def2, def3, def4}, ' '); end @@ -278,7 +182,7 @@ function definesUserArg = parseDefinesMaskText() end - +%% PARSE FUNCTIONS function out = parseCellString(str) str = strtrim(str); @@ -308,22 +212,94 @@ 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 -% +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 + + +%% CONSOLE FUNCTIONS + +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 diff --git a/periph_config.asv b/periph_config.asv index 5ec730c..2b420ab 100644 --- a/periph_config.asv +++ b/periph_config.asv @@ -1,7 +1,13 @@ { - "ADC1": { + "ADC": { "Defines": { - "ENABLE": { + "ADC1 Enable": { + "Def": "ADC1_ENABLE", + "Type": "checkbox", + "Default": true + }, + "ADC2 Enable": { + "Def": "ADC2_ENABLE", "Type": "checkbox", "Default": true }, @@ -11,15 +17,21 @@ } } }, - "USART1": { + "TIM": { "Defines": { - "ENABLE": { + "TIM1 Enable": { + "Def": "ADC1_ENABLE", "Type": "checkbox", - "Default": false + "Default": true }, - "BAUDRATE": { + "TIM2 Enable": { + "Def": "ADC2_ENABLE", + "Type": "checkbox", + "Default": true + }, + "AHB Buf Clock Rate": { "Type": "edit", - "Default": 115200 + "Default": 72 } } } diff --git a/periph_config.json b/periph_config.json index 5ec730c..8973e22 100644 --- a/periph_config.json +++ b/periph_config.json @@ -1,7 +1,13 @@ { - "ADC1": { + "ADC": { "Defines": { - "ENABLE": { + "ADC1 Enable": { + "Def": "ADC1_ENABLE", + "Type": "checkbox", + "Default": true + }, + "ADC2 Enable": { + "Def": "ADC2_ENABLE", "Type": "checkbox", "Default": true }, @@ -11,15 +17,21 @@ } } }, - "USART1": { + "TIM": { "Defines": { - "ENABLE": { + "TIM1 Enable": { + "Def": "ADC1_ENABLE", "Type": "checkbox", - "Default": false + "Default": true }, - "BAUDRATE": { + "TIM2 Enable": { + "Def": "ADC2_ENABLE", + "Type": "checkbox", + "Default": true + }, + "AHB Buf Clock Rate (MHz)": { "Type": "edit", - "Default": 115200 + "Default": 72 } } }