From edb22966ffb977755f07fef04133070409de654d Mon Sep 17 00:00:00 2001 From: Razvalyaev Date: Sun, 15 Jun 2025 10:55:05 +0300 Subject: [PATCH] =?UTF-8?q?=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83?= =?UTF-8?q?=D1=80=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BE:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit выделены отдельный файл для работы с wrapper и appwrapper --- McuLib/m/appWrap.m | 156 +++++++++++++++++++++++ McuLib/m/asynchManage.m | 4 +- McuLib/m/mainWrap.m | 72 +++++++++++ McuLib/m/mcuMask.m | 266 +++++++--------------------------------- 4 files changed, 272 insertions(+), 226 deletions(-) create mode 100644 McuLib/m/appWrap.m create mode 100644 McuLib/m/mainWrap.m diff --git a/McuLib/m/appWrap.m b/McuLib/m/appWrap.m new file mode 100644 index 0000000..14de84f --- /dev/null +++ b/McuLib/m/appWrap.m @@ -0,0 +1,156 @@ +classdef appWrap + + methods(Static) + function appWrapperFunc() + block = gcb; + % Получаем имя функции и путь к файлам + [filename, section, tool, example]= appWrap.getAppWrapperUserFile(block); + mcuMask.tool(tool, example); + + % Загружаем содержимое файла + set_param(block, 'appWrapperCode', ''); + try + code = fileread(filename); + code = regexprep(code, '\r\n?', '\n'); % нормализуем окончания строк + + includesText = editCode.extractSection(code, section); + set_param(block, 'appWrapperCode', includesText); + catch + end + % % Поиск тела обычной функции + % expr = sprintf('void %s()', sel); + % funcBody = editCode.extractSection(code, expr); + % set_param(block, 'wrapperCode', funcBody); + end + + function saveAppWrapperCode() + block = gcb; + + % Получаем имя функции и путь к файлам + [filename, section] = appWrap.getAppWrapperUserFile(block); + if ~isfile(filename) + errordlg(['Файл не найден: ', filename]); + return; + end + + sel = get_param(block, 'appWrapperFunc'); + basePath = get_param(block, 'appWrapperPath'); + if isempty(basePath) + errordlg('Не указан путь к файлам обёртки (wrapperPath).'); + return; + end + newBody = get_param(block, 'appWrapperCode'); + code = fileread(filename); + code = regexprep(code, '\r\n?', '\n'); + newBody = strrep(newBody, '\', '\\'); + code = editCode.insertSection(code, section, newBody); + % else + % % Обновляем тело функции + % expr = sprintf('void %s()', sel); + % code = editCode.insertSection(code, expr, newBody); + % end + fid = fopen(filename, 'w', 'n', 'UTF-8'); + if fid == -1 + errordlg('Не удалось открыть файл для записи'); + return; + end + fwrite(fid, code); + fclose(fid); + mcuMask.disp(1, ['Обновлено: ' sel]); + end + + function openAppWrapperCode() + block = gcb; + + % Получаем имя функции и путь к файлам + filename = appWrap.getAbsolutePath(mcuMask.getAppWrapperUserFile(block)); + if exist(filename, 'file') == 2 + % Формируем команду без кавычек + cmd = sprintf('rundll32.exe shell32.dll,OpenAs_RunDLL %s', filename); + status = system(cmd); + if status ~= 0 + errordlg('Не удалось открыть окно выбора приложения.'); + end + else + errordlg('Файл не найден'); + end + end + end + + +%% SPECIFIC TOOLS + methods(Static, Access = private) + + function [filename, section, tool, example] = getAppWrapperUserFile(block) + sel = get_param(block, 'appWrapperFunc'); + basePath = mcuPath.get('appWrapperPath'); + if isempty(basePath) + errordlg('Не указан путь к файлам обёртки (wrapperPath).'); + return; + end + % Формируем путь к файлу в зависимости от типа запроса + if strcmp(sel, 'Includes') + filename = fullfile(basePath, 'app_includes.h'); + section = '// INCLUDES'; + tool = 'Инклюды для доступа к коду МК в коде оболочке'; + example = '#include "main.h"'; + elseif strcmp(sel, 'Dummy') + filename = fullfile(basePath, 'app_wrapper.c'); + section = '// DUMMY'; + tool = 'Заглушки для различных функций и переменных'; + example = ['CAN_HandleTypeDef hcan = {0};' newline... + 'void hardware_func(handle *huart) {}' newline... + 'int wait_for_hardware_flag(int *flag) {' newline... + ' return 1;' newline... + '}' newline... + '']; + elseif strcmp(sel, 'App Init') + filename = fullfile(basePath, 'app_init.c'); + section = '// USER APP INIT'; + tool = ['Код для инициализации приложения МК.' newline newline... + 'Вызов функций инициализации, если не используется отдельный поток для main().']; + example = 'init_func();'; + elseif strcmp(sel, 'App Step') + filename = fullfile(basePath, 'app_wrapper.c'); + section = '// USER APP STEP'; + tool = ['Код приложения МК для вызова в шаге симуляции.' newline newline ... + 'Вызов функций программы МК, если не используется отдельный поток для main().']; + example = 'step_func();'; + elseif strcmp(sel, 'App Inputs') + filename = fullfile(basePath, 'app_io.c'); + section = '// USER APP INPUT'; + tool = ['Работа с буффером для портов S-Function' newline newline ... + 'Буфер в начале хранит входные порты S-Function, далее идут выходные порты:' newline ... + 'Buffer[0:15] - входной порт, Buffer[16:31] - входной 1 порт, ' newline ... + 'Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт']; + example = ['// чтение 1-го элемента 0-го входного массива' newline... + 'app_variable_2 = ReadInputArray(0, 1);' newline newline... + '// запись в буфер выходов' newline ... + 'app_variable_2 = Buffer[10];']; + elseif strcmp(sel, 'App Outputs') + filename = fullfile(basePath, 'app_io.c'); + section = '// USER APP OUTPUT'; + tool = ['Работа с буффером для портов S-Function' newline newline ... + 'Буфер в начале хранит входные порты S-Function, далее идут выходные порты:' newline ... + 'Buffer[0:15] - входной порт, Buffer[16:31] - входной 1 порт, ' newline ... + 'Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт']; + example = ['// запись в 1-й элемент 0-го выходного массива' newline... + 'WriteOutputArray(app_variable, 0, 1);' newline newline ... + '// запись в буфер выходов' newline ... + 'Buffer[XD_OUTPUT_START + 10] = app_variable_2;']; + elseif strcmp(sel, 'App Deinit') + filename = fullfile(basePath, 'app_init.c'); + section = '// USER APP DEINIT'; + tool = ['Код для деинициализации приложения МК.' newline newline ... + 'Можно деинициализировать приложение МК, для повторного запуска.']; + example = 'memset(&htim1, sizeof(htim1), 0;'; + else + tool = ''; + mcuMask.disp(0, '\nОшибка выбора типа секции кода: неизвестное значение'); + end + + end + + end + +end \ No newline at end of file diff --git a/McuLib/m/asynchManage.m b/McuLib/m/asynchManage.m index 591139d..71f1834 100644 --- a/McuLib/m/asynchManage.m +++ b/McuLib/m/asynchManage.m @@ -39,7 +39,7 @@ classdef asynchManage < handle methods (Access = private) function saveCallback(obj) try - mcuMask.saveAndClose(obj.maskBlockPath); + mcuMask.close(obj.maskBlockPath); save_system(obj.modelName); catch ME warning('progr:Nneg', 'Ошибка при сохранении модели: %s', ME.message); @@ -79,7 +79,7 @@ classdef asynchManage < handle function GUIconfigCallback(obj) try - mcuMask.saveAndClose(obj.maskBlockPath); + mcuMask.close(obj.maskBlockPath); mexing(0); catch ME warning('progr:Nneg', 'Ошибка при обновлении модели: %s', ME.message); diff --git a/McuLib/m/mainWrap.m b/McuLib/m/mainWrap.m new file mode 100644 index 0000000..dcc3c17 --- /dev/null +++ b/McuLib/m/mainWrap.m @@ -0,0 +1,72 @@ +classdef mainWrap + + methods(Static) + function enableThreading() + block = gcb; + maskNames = get_param(block, 'MaskNames'); + maskValues = get_param(block, 'MaskValues'); + maskEnables = get_param(block, 'MaskEnables'); + idxEnable = find(strcmp(maskNames, 'enableThreading')); + idxEdit = find(strcmp(maskNames, 'threadCycles')); + if isempty(idxEnable) || isempty(idxEdit) + error('Параметры enableThreading или threadCycles не найдены в маске'); + end + val = maskValues{idxEnable}; + if strcmp(val, 'on') + maskEnables{idxEdit} = 'on'; + else + maskEnables{idxEdit} = 'off'; + end + set_param(block, 'MaskEnables', maskEnables); + end + + function enableDeinit() + block = gcb; + maskNames = get_param(block, 'MaskNames'); + maskValues = get_param(block, 'MaskValues'); + maskEnables = get_param(block, 'MaskEnables'); + idxEnable = find(strcmp(maskNames, 'enableThreading')); + idxEdit = find(strcmp(maskNames, 'threadCycles')); + if isempty(idxEnable) || isempty(idxEdit) + error('Параметры enableThreading или threadCycles не найдены в маске'); + end + val = maskValues{idxEnable}; + if strcmp(val, 'on') + maskEnables{idxEdit} = 'on'; + else + maskEnables{idxEdit} = 'off'; + end + set_param(block, 'MaskEnables', maskEnables); + end + + function extConsol() + block = gcb; + mask = Simulink.Mask.get(block); + fullOut = mask.getParameter('fullOutput'); + extCons = mask.getParameter('extConsol'); + if isempty(extCons) || isempty(fullOut) + error('Параметры fullOutput или extConsol не найдены в маске'); + end + + if(strcmp(extCons.Enabled, 'on')) + if strcmp(extCons.Value, 'on') + fullOut.Enabled = 'off'; + fullOut.Value = 'on'; + else + fullOut.Enabled = 'on'; + end + else + fullOut.Enabled = 'on'; + end + + end + + end + + +%% SPECIFIC TOOLS + methods(Static, Access = private) + + end + +end \ No newline at end of file diff --git a/McuLib/m/mcuMask.m b/McuLib/m/mcuMask.m index 8467eb8..8e36778 100644 --- a/McuLib/m/mcuMask.m +++ b/McuLib/m/mcuMask.m @@ -1,5 +1,5 @@ classdef mcuMask - +%% CALLBACKS methods(Static) % Following properties of 'maskInitContext' are avalaible to use: % - BlockHandle @@ -58,148 +58,37 @@ classdef mcuMask end %% WRAPPER PARAMS - function enableThreading(callbackContext) - block = gcb; - maskNames = get_param(block, 'MaskNames'); - maskValues = get_param(block, 'MaskValues'); - maskEnables = get_param(block, 'MaskEnables'); - idxEnable = find(strcmp(maskNames, 'enableThreading')); - idxEdit = find(strcmp(maskNames, 'threadCycles')); - if isempty(idxEnable) || isempty(idxEdit) - error('Параметры enableThreading или threadCycles не найдены в маске'); - end - val = maskValues{idxEnable}; - if strcmp(val, 'on') - maskEnables{idxEdit} = 'on'; - else - maskEnables{idxEdit} = 'off'; - end - set_param(block, 'MaskEnables', maskEnables); - end - - function enableDeinit(callbackContext) - block = gcb; - maskNames = get_param(block, 'MaskNames'); - maskValues = get_param(block, 'MaskValues'); - maskEnables = get_param(block, 'MaskEnables'); - idxEnable = find(strcmp(maskNames, 'enableThreading')); - idxEdit = find(strcmp(maskNames, 'threadCycles')); - if isempty(idxEnable) || isempty(idxEdit) - error('Параметры enableThreading или threadCycles не найдены в маске'); - end - val = maskValues{idxEnable}; - if strcmp(val, 'on') - maskEnables{idxEdit} = 'on'; - else - maskEnables{idxEdit} = 'off'; - end - set_param(block, 'MaskEnables', maskEnables); - end - - function extConsol(callbackContext) - block = gcb; - mask = Simulink.Mask.get(block); - fullOut = mask.getParameter('fullOutput'); - extCons = mask.getParameter('extConsol'); - if isempty(extCons) || isempty(fullOut) - error('Параметры fullOutput или extConsol не найдены в маске'); - end - - if(strcmp(extCons.Enabled, 'on')) - if strcmp(extCons.Value, 'on') - fullOut.Enabled = 'off'; - fullOut.Value = 'on'; - else - fullOut.Enabled = 'on'; - end - else - fullOut.Enabled = 'on'; - end - - end - 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 - %% USER WRAPPER CODE function appWrapperFunc(callbackContext) - block = gcb; - % Получаем имя функции и путь к файлам - [filename, section, tool, example]= mcuMask.getWrapperUserFile(block); - mcuMask.tool(tool, example); - - % Загружаем содержимое файла - set_param(block, 'appWrapperCode', ''); - try - code = fileread(filename); - code = regexprep(code, '\r\n?', '\n'); % нормализуем окончания строк - - includesText = editCode.extractSection(code, section); - set_param(block, 'appWrapperCode', includesText); - catch - end - % % Поиск тела обычной функции - % expr = sprintf('void %s()', sel); - % funcBody = editCode.extractSection(code, expr); - % set_param(block, 'wrapperCode', funcBody); + appWrap.appWrapperFunc(); end function saveAppWrapperCode(callbackContext) - block = gcb; - - % Получаем имя функции и путь к файлам - [filename, section] = mcuMask.getWrapperUserFile(block); - if ~isfile(filename) - errordlg(['Файл не найден: ', filename]); - return; - end - - sel = get_param(block, 'appWrapperFunc'); - basePath = get_param(block, 'appWrapperPath'); - if isempty(basePath) - errordlg('Не указан путь к файлам обёртки (wrapperPath).'); - return; - end - newBody = get_param(block, 'appWrapperCode'); - code = fileread(filename); - code = regexprep(code, '\r\n?', '\n'); - newBody = strrep(newBody, '\', '\\'); - code = editCode.insertSection(code, section, newBody); - % else - % % Обновляем тело функции - % expr = sprintf('void %s()', sel); - % code = editCode.insertSection(code, expr, newBody); - % end - fid = fopen(filename, 'w', 'n', 'UTF-8'); - if fid == -1 - errordlg('Не удалось открыть файл для записи'); - return; - end - fwrite(fid, code); - fclose(fid); - mcuMask.disp(1, ['Обновлено: ' sel]); + appWrap.saveAppWrapperCode(); end function openAppWrapperCode(callbackContext) - block = gcb; - - % Получаем имя функции и путь к файлам - filename = mcuPath.getAbsolutePath(mcuMask.getWrapperUserFile(block)); - if exist(filename, 'file') == 2 - % Формируем команду без кавычек - cmd = sprintf('rundll32.exe shell32.dll,OpenAs_RunDLL %s', filename); - status = system(cmd); - if status ~= 0 - errordlg('Не удалось открыть окно выбора приложения.'); - end - else - errordlg('Файл не найден'); - end + appWrap.openAppWrapperCode(); end %% USER CODE @@ -220,36 +109,23 @@ classdef mcuMask 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 updateModel(callbackContext) - 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 findjobj_link(callbackContext) - web('https://www.mathworks.com/matlabcentral/fileexchange/14317-findjobj-find-java-handles-of-matlab-graphic-objects'); - end - - function set_name(callbackContext) + function setSFuncName(callbackContext) block = gcb; % Получаем параметр имени S-Function из маски блока newName = mcuMask.get_name(); @@ -282,88 +158,30 @@ classdef mcuMask fwrite(fid, updatedText); fclose(fid); end - end - - -%% SPECIFIC TOOLS - methods(Static, Access = private) - - function [filename, section, tool, example] = getWrapperUserFile(block) - sel = get_param(block, 'appWrapperFunc'); - basePath = mcuPath.get('appWrapperPath'); - if isempty(basePath) - errordlg('Не указан путь к файлам обёртки (wrapperPath).'); - return; - end - % Формируем путь к файлу в зависимости от типа запроса - if strcmp(sel, 'Includes') - filename = fullfile(basePath, 'app_includes.h'); - section = '// INCLUDES'; - tool = 'Инклюды для доступа к коду МК в коде оболочке'; - example = '#include "main.h"'; - elseif strcmp(sel, 'Dummy') - filename = fullfile(basePath, 'app_wrapper.c'); - section = '// DUMMY'; - tool = 'Заглушки для различных функций и переменных'; - example = ['CAN_HandleTypeDef hcan = {0};' newline... - 'void hardware_func(handle *huart) {}' newline... - 'int wait_for_hardware_flag(int *flag) {' newline... - ' return 1;' newline... - '}' newline... - '']; - elseif strcmp(sel, 'App Init') - filename = fullfile(basePath, 'app_init.c'); - section = '// USER APP INIT'; - tool = ['Код для инициализации приложения МК.' newline newline... - 'Вызов функций инициализации, если не используется отдельный поток для main().']; - example = 'init_func();'; - elseif strcmp(sel, 'App Step') - filename = fullfile(basePath, 'app_wrapper.c'); - section = '// USER APP STEP'; - tool = ['Код приложения МК для вызова в шаге симуляции.' newline newline ... - 'Вызов функций программы МК, если не используется отдельный поток для main().']; - example = 'step_func();'; - elseif strcmp(sel, 'App Inputs') - filename = fullfile(basePath, 'app_io.c'); - section = '// USER APP INPUT'; - tool = ['Работа с буффером для портов S-Function' newline newline ... - 'Буфер в начале хранит входные порты S-Function, далее идут выходные порты:' newline ... - 'Buffer[0:15] - входной порт, Buffer[16:31] - входной 1 порт, ' newline ... - 'Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт']; - example = ['// чтение 1-го элемента 0-го входного массива' newline... - 'app_variable_2 = ReadInputArray(0, 1);' newline newline... - '// запись в буфер выходов' newline ... - 'app_variable_2 = Buffer[10];']; - elseif strcmp(sel, 'App Outputs') - filename = fullfile(basePath, 'app_io.c'); - section = '// USER APP OUTPUT'; - tool = ['Работа с буффером для портов S-Function' newline newline ... - 'Буфер в начале хранит входные порты S-Function, далее идут выходные порты:' newline ... - 'Buffer[0:15] - входной порт, Buffer[16:31] - входной 1 порт, ' newline ... - 'Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт']; - example = ['// запись в 1-й элемент 0-го выходного массива' newline... - 'WriteOutputArray(app_variable, 0, 1);' newline newline ... - '// запись в буфер выходов' newline ... - 'Buffer[XD_OUTPUT_START + 10] = app_variable_2;']; - elseif strcmp(sel, 'App Deinit') - filename = fullfile(basePath, 'app_init.c'); - section = '// USER APP DEINIT'; - tool = ['Код для деинициализации приложения МК.' newline newline ... - 'Можно деинициализировать приложение МК, для повторного запуска.']; - example = 'memset(&htim1, sizeof(htim1), 0;'; - else - tool = ''; - mcuMask.disp(0, '\nОшибка выбора типа секции кода: неизвестное значение'); - 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 saveAndClose(blockPath) + 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);