diff --git a/MCU_Wrapper/mcu_wrapper.c b/MCU_Wrapper/mcu_wrapper.c index f7e212d..2c5b73a 100644 --- a/MCU_Wrapper/mcu_wrapper.c +++ b/MCU_Wrapper/mcu_wrapper.c @@ -58,14 +58,15 @@ void MCU_Step_Simulation(SimStruct* S, time_T time) MCU_Periph_Simulation(); // simulate peripheral - extern void upp_main(void); - upp_main(); #ifdef RUN_APP_MAIN_FUNC_THREAD ResumeThread(hmcu.hMCUThread); for (int i = DEKSTOP_CYCLES_FOR_MCU_APP; i > 0; i--) { } SuspendThread(hmcu.hMCUThread); +#else + extern void upp_main(void); + upp_main(); #endif //RUN_APP_MAIN_FUNC_THREAD MCU_writeOutputs(S); // запись портов (по факту запись в буфер. запись в порты в mdlOutputs) @@ -152,13 +153,14 @@ void SIM_Initialize_Simulation(void) #ifdef RUN_APP_MAIN_FUNC_THREAD // инициализация потока, который будет выполнять код МК hmcu.hMCUThread = (HANDLE)CreateThread(NULL, 0, MCU_App_Thread, 0, CREATE_SUSPENDED, &hmcu.idMCUThread); +#else + extern int main_init(void); + main_init(); #endif //RUN_APP_MAIN_FUNC_THREAD /* user initialization */ Initialize_Periph_Sim(); - extern int main_init(void); - main_init(); /* wrapper initialization */ hmcu.SystemClock_step = MCU_CORE_CLOCK * hmcu.SIM_Sample_Time; // set system clock step } diff --git a/MCU_Wrapper/run_mex.bat b/MCU_Wrapper/run_mex.bat index d268403..15fda3b 100644 --- a/MCU_Wrapper/run_mex.bat +++ b/MCU_Wrapper/run_mex.bat @@ -20,9 +20,7 @@ set compil_mode=%~4 set defines_USER=%defines_USER:__EQ__==% -set defines_WRAPPER=-D"STM32F103xB" -D"USE_HAL_DRIVER"^ - -D"MATLAB"^ - -D"__sizeof_ptr=8" +set defines_WRAPPER=-D"MATLAB"^ -D"__sizeof_ptr=8" :: -------------------------USERS PATHS AND CODE--------------------------- ::------------------------------------------------------------------------- @@ -135,7 +133,5 @@ echo =========================== echo MODE: %compil_mode% echo =========================== - -echo mex %output% %defines% %includes% %codes% %debug% mex %output% %defines% %includes% %codes% %debug% echo %DATE% %TIME% \ No newline at end of file diff --git a/findjobj.mltbx b/findjobj.mltbx new file mode 100644 index 0000000..fda256a Binary files /dev/null and b/findjobj.mltbx differ diff --git a/mcu_test_r2023.slx b/mcu_test_r2023.slx index 192e203..9d1f4a9 100644 Binary files a/mcu_test_r2023.slx and b/mcu_test_r2023.slx differ diff --git a/mexing.m b/mexing.m index 21f81e7..d46ff95 100644 --- a/mexing.m +++ b/mexing.m @@ -1,13 +1,24 @@ % Компилирует S-function clear, clc +close; + Ts = 0.00001; % Флаг режима отладки 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')); + +isDebug = maskValues{inxDebug}; +isExtConsole = maskValues{idxExtConsole}; -maskNames = get_param(gcbh, 'MaskNames'); -isDebug = find(strcmp(maskNames, 'enableDebug')); if strcmpi(isDebug, 'on') modeArg = "release"; else @@ -16,17 +27,27 @@ 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', includesArg, codeArg, definesArg, modeArg); +cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" %s', includesArg, codeArg, definesAllArg, modeArg); -status = system(cmd); - -if status == 0 - beep +if(strcmpi(isExtConsole, 'on')) + cmdout = runBatAndShowOutput(cmd); else - error('Error during compilation'); + [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) @@ -67,6 +88,83 @@ 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() blockHandle = gcbh; @@ -75,35 +173,96 @@ function definesArg = buildDefinesString() paramNames = get_param(blockHandle, 'MaskNames'); % Индексы параметров - idxEnable = find(strcmp(paramNames, 'enableThreading')); + idxThreading = find(strcmp(paramNames, 'enableThreading')); + idxDeinit = find(strcmp(paramNames, 'enableDeinit')); idxCycles = find(strcmp(paramNames, 'threadCycles')); idxClk = find(strcmp(paramNames, 'mcuClk')); - if any([isempty(idxEnable), isempty(idxCycles), isempty(idxClk)]) + if any([isempty(idxThreading), isempty(idxDeinit),isempty(idxCycles), isempty(idxClk)]) error('Один или несколько параметров не найдены в маске'); end % Значения - enableVal = maskValues{idxEnable}; + ThreadingVal = maskValues{idxThreading}; + DeinitVal = maskValues{idxDeinit}; cyclesVal = maskValues{idxCycles}; clkMHz = str2double(maskValues{idxClk}); clkHz = round(clkMHz * 1e6); % Формируем defines в формате: -D"NAME=VALUE" - if strcmpi(enableVal, 'on') + if strcmpi(ThreadingVal, 'on') def1 = ['-D"RUN_APP_MAIN_FUNC_THREAD"']; else def1 = ['']; end - def2 = ['-D"DEKSTOP_CYCLES_FOR_MCU_APP__EQ__' cyclesVal '"']; - def3 = ['-D"MCU_CORE_CLOCK__EQ__' num2str(clkHz) '"']; - definesArg = strjoin({def1, def2, def3}, ' '); + 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); @@ -131,6 +290,8 @@ function str = cellArrayToString(cellArray) str = ['{' strjoin(quoted, ';') '}']; end + + % % Компилирует S-function % clear, clc, %