classdef mcuPorts methods(Static) function write() block = gcb; mask = Simulink.Mask.get(block); hPath = fullfile(mcuPath.get('wrapperPath'), 'mcu_wrapper_conf.h'); cPath = fullfile(mcuPath.get('wrapperPath'), 'mcu_wrapper.c'); mcuPorts.defaultUnused(); %% CREATE prefixNumb = 'IN'; [widths, portPrefixes] = mcuPorts.getMaskNames('in'); headerText = mcuPorts.addPortHeaderDefines('', widths, prefixNumb, portPrefixes); cText = mcuPorts.addPortCDefines('', widths, prefixNumb, portPrefixes); prefixNumb = 'OUT'; [widths, portPrefixes] = mcuPorts.getMaskNames('out'); headerText = mcuPorts.addPortHeaderDefines(headerText, widths, prefixNumb, portPrefixes); cText = mcuPorts.addPortCDefines(cText, widths, prefixNumb, portPrefixes); %% WRITE hCode = fileread(hPath); hCode = regexprep(hCode, '\r\n?', '\n'); cCode = fileread(cPath); cCode = regexprep(cCode, '\r\n?', '\n'); code = editCode.insertSection(hCode, '// INPUT/OUTPUTS PARAMS', headerText.PARAMS); code = editCode.insertSection(code, '// INPUT/OUTPUTS AUTO-PARAMS', headerText.AUTO_PARAMS); fid = fopen(hPath, 'w', 'n', 'UTF-8'); if fid == -1 error('Не удалось открыть файл для записи'); end fwrite(fid, code); fclose(fid); code = editCode.insertSection(cCode, '// INPUT/OUTPUTS AUTO-PARAMS', cText); fid = fopen(cPath, 'w', 'n', 'UTF-8'); if fid == -1 error('Не удалось открыть файл для записи'); end fwrite(fid, code); fclose(fid); end function [portwidth, defnames] = getMaskNames(port_prefix) block = gcb; % Получаем значение из спиннера mask = Simulink.Mask.get(block); paramName = sprintf('%sNumb', port_prefix); param = mask.getParameter(paramName); numb = str2double(param.Value); % Инициализируем массив для значений defnames = strings(1, numb); portwidth = []; % Чтение значений edit-параметров for i = 1:numb paramName = sprintf('%s_port_%d_name', port_prefix, i); param = mask.getParameter(paramName); defnames(i) = param.Value; paramName = sprintf('%s_port_%d_width', port_prefix, i); param = mask.getParameter(paramName); portwidth(i) = str2double(param.Value); end end function updateMask() mcuPorts.updateMask_prefix('in'); mcuPorts.updateMask_prefix('out'); end function defaultUnused() mcuPorts.defaultUnused_prefix('in'); mcuPorts.defaultUnused_prefix('out'); end end methods(Static, Access=private) function updateMask_prefix(port_prefix) block = gcb; % Получаем значение из спиннера mask = Simulink.Mask.get(block); paramName = sprintf('%sNumb', port_prefix); param = mask.getParameter(paramName); n = str2double(param.Value); % Максимальное количество портов maxPorts = param.Range(2); % Проходим по всем edit-полям for i = 1:maxPorts % Формируем имя параметра paramDefName = sprintf('%s_port_%d_name', port_prefix, i); paramWidthName = sprintf('%s_port_%d_width', port_prefix, i); paramDef = mask.getParameter(paramDefName); paramWidth = mask.getParameter(paramWidthName); if i <= n % Показываем параметр paramDef.Visible = 'on'; paramWidth.Visible = 'on'; % Если значение пустое — задаём дефолтное if isempty(strtrim(paramDef.Value)) paramDef.Value = upper(port_prefix); end % Если значение пустое — задаём дефолтное if isempty(strtrim(paramWidth.Value)) || strcmp(paramWidth.Value, '0') paramWidth.Value = '16'; end else % Скрываем параметр paramDef.Visible = 'off'; paramWidth.Visible = 'off'; end end end function defaultUnused_prefix(port_prefix) block = gcb; % Получаем значение из спиннера mask = Simulink.Mask.get(block); paramName = sprintf('%sNumb', port_prefix); param = mask.getParameter(paramName); numb = str2double(param.Value); % Максимальное количество портов maxPorts = param.Range(2); % Чтение значений edit-параметров for i = numb+1:maxPorts paramName = sprintf('%s_port_%d_name', port_prefix, i); param = mask.getParameter(paramName); param.Value = upper(port_prefix); paramName = sprintf('%s_port_%d_width', port_prefix, i); param = mask.getParameter(paramName); param.Value = '16'; end end function headerText = addPortHeaderDefines(existingText, widths, prefixNumb, portPrefixes) % existingText — структура с полями PARAMS, AUTO_PARAMS % widths — вектор ширин портов % prefixNumb — префикс общего счётчика (например, 'OUT') % portPrefixes — {'OUT', 'OUT', ...} n = numel(widths); upperPrefix = upper(prefixNumb); % === PARAMS === lines = { sprintf('#define %s_PORT_NUMB %d', upperPrefix, n) }; for i = 1:n lines{end+1} = sprintf('#define %s_PORT_%d_WIDTH %d', ... upper(portPrefixes{i}), i, widths(i)); end newParams = strjoin(lines, newline); newParams = [newParams, newline]; % === AUTO-PARAMS === lines = {}; % Формируем выражение суммы ширин с добавлением PORT sumExprParts = cell(1,n); for i = 1:n sumExprParts{i} = sprintf('%s_PORT_%d_WIDTH', upper(portPrefixes{i}), i); end sumExpr = strjoin(sumExprParts, ' + '); lines{end+1} = sprintf('/// === Полный размер буфера ==='); lines{end+1} = sprintf('#define TOTAL_%s_SIZE (%s)', upperPrefix, sumExpr); lines{end+1} = ''; lines{end+1} = sprintf('/// === Смещения массивов (внутри общего буфера) ==='); for i = 1:n if i == 1 lines{end+1} = sprintf('#define OFFSET_%s_ARRAY_1 0', upperPrefix); else lines{end+1} = sprintf('#define OFFSET_%s_ARRAY_%d (OFFSET_%s_ARRAY_%d + %s_PORT_%d_WIDTH)', ... upperPrefix, i, upperPrefix, i - 1, upper(portPrefixes{i - 1}), i - 1); end end newAuto = strjoin(lines, newline); % === Добавление к существующему === if isfield(existingText, 'PARAMS') headerText.PARAMS = [existingText.PARAMS, newline, newParams]; else headerText.PARAMS = newParams; end if isfield(existingText, 'AUTO_PARAMS') headerText.AUTO_PARAMS = [existingText.AUTO_PARAMS, newline, newAuto, newline]; else headerText.AUTO_PARAMS = [newAuto, newline]; end end function cText = addPortCDefines(existingText, widths, prefixNumb, portPrefixes) % existingText — существующий текст .c % widths — вектор ширин портов % prefixNumb — общий префикс ('OUT') % portPrefixes — {'OUT', 'LOG', ...} n = numel(widths); upperPrefix = upper(prefixNumb); lowerPrefix = lower(prefixNumb); lines = {}; % === Таблица длин === lines{end+1} = '/**'; lines{end+1} = sprintf(' * @brief Таблица длин массивов %s', upperPrefix); lines{end+1} = ' */'; % Здесь используем общий префикс для количества портов lines{end+1} = sprintf('const int %sLengths[%s_PORT_NUMB] = {', lowerPrefix, upperPrefix); for i = 1:n comma = ','; if i == n comma = ''; end % Используем макросы с портовыми префиксами из portPrefixes lines{end+1} = sprintf(' %s_PORT_%d_WIDTH%s', upper(portPrefixes{i}), i, comma); end lines{end+1} = '};'; % === Таблица смещений === lines{end+1} = '/**'; lines{end+1} = sprintf(' * @brief Таблица смещений в выходном массиве %s', upperPrefix); lines{end+1} = ' */'; lines{end+1} = sprintf('const int %sOffsets[%s_PORT_NUMB] = {', lowerPrefix, upperPrefix); for i = 1:n comma = ','; if i == n comma = ''; end lines{end+1} = sprintf(' OFFSET_%s_ARRAY_%d%s', upperPrefix, i, comma); end lines{end+1} = '};'; lines{end+1} = ''; newText = strjoin(lines, newline); if nargin < 1 || isempty(existingText) cText = newText; else cText = [existingText, newline, newText]; end end function val = iff(cond, a, b) % Условное выражение inline if cond val = a; else val = b; end end end end