Compare commits
5 Commits
v1.0
...
245592a821
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
245592a821 | ||
|
|
0a2fd71422 | ||
|
|
966ddc3bac | ||
|
|
df30570d4a | ||
|
|
d983f2525a |
BIN
MCU Wrapper.mltbx
Normal file
BIN
MCU Wrapper.mltbx
Normal file
Binary file not shown.
@@ -7,41 +7,7 @@ function install_my_library()
|
||||
addpath(fullfile(libDir, 'm'));
|
||||
savepath;
|
||||
|
||||
% 2. Диалог выбора папки для копирования шаблонов
|
||||
defaultTargetDir = pwd;
|
||||
answer = questdlg(['Выберите папку для копирования шаблонов кода. ', ...
|
||||
'По умолчанию текущая папка: ' defaultTargetDir], ...
|
||||
'Выбор папки', ...
|
||||
'Текущая папка', 'Выбрать другую', 'Текущая папка');
|
||||
|
||||
switch answer
|
||||
case 'Выбрать другую'
|
||||
targetDir = uigetdir(defaultTargetDir, 'Выберите папку для шаблонов');
|
||||
if isequal(targetDir,0)
|
||||
disp('Копирование шаблонов отменено пользователем.');
|
||||
targetDir = '';
|
||||
end
|
||||
case 'Текущая папка'
|
||||
targetDir = defaultTargetDir;
|
||||
otherwise
|
||||
targetDir = defaultTargetDir;
|
||||
end
|
||||
|
||||
if ~isempty(targetDir)
|
||||
templatesDir = fullfile(libDir, 'templates');
|
||||
templateFiles = dir(fullfile(templatesDir, '*.*'));
|
||||
for k = 1:numel(templateFiles)
|
||||
if ~templateFiles(k).isdir
|
||||
copyfile(fullfile(templatesDir, templateFiles(k).name), ...
|
||||
fullfile(targetDir, templateFiles(k).name));
|
||||
end
|
||||
end
|
||||
fprintf('Шаблоны кода скопированы в папку:\n%s\n', targetDir);
|
||||
end
|
||||
|
||||
% 3. Обновляем Library Browser
|
||||
rehash;
|
||||
sl_refresh_customizations;
|
||||
|
||||
disp('Библиотека успешно установлена и добавлена в Library Browser.');
|
||||
end
|
||||
|
||||
Binary file not shown.
@@ -67,7 +67,6 @@ classdef asynchManage < handle
|
||||
if ~isempty(obj.maskBlockPath)
|
||||
try
|
||||
mcuMask.open(obj.maskBlockPath, 1);
|
||||
fprintf('Mask opened for block %s\n', obj.maskBlockPath);
|
||||
catch ME
|
||||
warning('progr:Nneg', 'Не удалось открыть маску: %s', ME.message);
|
||||
end
|
||||
|
||||
139
McuLib/m/compiler.m
Normal file
139
McuLib/m/compiler.m
Normal file
@@ -0,0 +1,139 @@
|
||||
classdef compiler
|
||||
methods(Static)
|
||||
|
||||
function compile()
|
||||
addpath(mcuPath.get('wrapperPath'));
|
||||
mexing(1);
|
||||
end
|
||||
|
||||
function get_availbe()
|
||||
addpath(mcuPath.get('wrapperPath'));
|
||||
mexing(1);
|
||||
end
|
||||
|
||||
function choose()
|
||||
addpath(mcuPath.get('wrapperPath'));
|
||||
mexing(1);
|
||||
end
|
||||
|
||||
|
||||
|
||||
function updateRunBat()
|
||||
sources = {
|
||||
'MCU.c'
|
||||
'mcu_wrapper.c'
|
||||
};
|
||||
% Список заголовочных файлов (.h)
|
||||
includes = { '.\'
|
||||
};
|
||||
periphPath = mcuPath.get('wrapperPath');
|
||||
% Формируем строки
|
||||
wrapperSrcText = compiler.createSourcesBat('code_WRAPPER', sources, periphPath);
|
||||
wrapperIncText = compiler.createIncludesBat('includes_WRAPPER', includes, periphPath);
|
||||
|
||||
% Записываем результат
|
||||
res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: WRAPPER BAT'); % Всё прошло успешно
|
||||
|
||||
if res == 0
|
||||
return
|
||||
end
|
||||
|
||||
sources = {
|
||||
'app_wrapper.c'
|
||||
'app_init.c'
|
||||
'app_io.c'
|
||||
};
|
||||
% Список заголовочных файлов (.h)
|
||||
includes = { '.\'
|
||||
};
|
||||
periphPath = mcuPath.get('appWrapperPath');
|
||||
% Формируем строки
|
||||
wrapperSrcText = compiler.createSourcesBat('code_APP_WRAPPER', sources, periphPath);
|
||||
wrapperIncText = compiler.createIncludesBat('includes_APP_WRAPPER', includes, periphPath);
|
||||
|
||||
% Записываем результат
|
||||
res = compiler.updateRunMexBat(wrapperSrcText, wrapperIncText, ':: APP WRAPPER BAT'); % Всё прошло успешно
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
function res = updateRunMexBat(srcText, incText, Section)
|
||||
% Входные параметры:
|
||||
% srcText - текст для записи set code_...
|
||||
% incText - текст для записи set includes_...
|
||||
%
|
||||
% Возвращает:
|
||||
% res - 0 при успехе, 1 при ошибке
|
||||
periphBat = [srcText '\n\n' incText];
|
||||
batPath = fullfile(mcuPath.get('wrapperPath'), 'run_mex.bat');
|
||||
res = 1;
|
||||
try
|
||||
code = fileread(batPath);
|
||||
code = regexprep(code, '\r\n?', '\n');
|
||||
|
||||
% Записываем строки srcText и incText с переносами строк
|
||||
code = editCode.insertSection(code, Section, periphBat);
|
||||
|
||||
fid = fopen(batPath, 'w', 'n', 'UTF-8');
|
||||
if fid == -1
|
||||
error('Не удалось открыть файл для записи');
|
||||
end
|
||||
fwrite(fid, code);
|
||||
fclose(fid);
|
||||
res = 1;
|
||||
catch ME
|
||||
mcuMask.disp(0, '\nОшибка: неудачная запись в файл при записи файла: %s', ME.message);
|
||||
end
|
||||
end
|
||||
|
||||
function srcText = createSourcesBat(prefix_name, sources, path)
|
||||
srcList = {};
|
||||
if nargin >= 2 && iscell(sources)
|
||||
for i = 1:numel(sources)
|
||||
fullPath = fullfile(path, sources{i});
|
||||
srcList{end+1} = strrep(fullPath, '\', '\\');
|
||||
end
|
||||
end
|
||||
|
||||
% Формируем srcText с переносами строк и ^
|
||||
srcText = '';
|
||||
for i = 1:numel(srcList)
|
||||
if i < numel(srcList)
|
||||
srcText = [srcText srcList{i} '^' newline ' '];
|
||||
else
|
||||
srcText = [srcText srcList{i}];
|
||||
end
|
||||
end
|
||||
|
||||
% Добавляем префикс
|
||||
srcText = ['set ' prefix_name '=' srcText];
|
||||
end
|
||||
|
||||
function incText = createIncludesBat(prefix_name, includes, path)
|
||||
incList = {};
|
||||
if nargin >= 2 && iscell(includes)
|
||||
for i = 1:numel(includes)
|
||||
fullPath = fullfile(path, includes{i});
|
||||
incList{end+1} = ['-I"' strrep(fullPath, '\', '\\') '"'];
|
||||
end
|
||||
end
|
||||
|
||||
% Формируем incText с переносами строк и ^
|
||||
incText = '';
|
||||
for i = 1:numel(incList)
|
||||
if i == 1 && numel(incList) ~= 1
|
||||
incText = [incText incList{i} '^' newline];
|
||||
elseif i < numel(incList)
|
||||
incText = [incText ' ' incList{i} '^' newline];
|
||||
else
|
||||
incText = [incText ' ' incList{i}];
|
||||
end
|
||||
end
|
||||
|
||||
% Добавляем префикс
|
||||
incText = ['set ' prefix_name '=' incText];
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -8,13 +8,13 @@ classdef customtable
|
||||
tableControl = mask.getDialogControl(table_name);
|
||||
tableParameter = mask.getParameter(table_name);
|
||||
nCols = tableControl.getNumberOfColumns;
|
||||
if nCols > 0
|
||||
for i = 1:nCols
|
||||
tableControl.removeColumn(1);
|
||||
end
|
||||
end
|
||||
column = tableControl.addColumn(Name='Title', Type='edit');
|
||||
tableControl.Sortable = 'on';
|
||||
% if nCols > 0
|
||||
% for i = 1:nCols
|
||||
% tableControl.removeColumn(1);
|
||||
% end
|
||||
% end
|
||||
% column = tableControl.addColumn(Name='Title', Type='edit');
|
||||
% tableControl.Sortable = 'on';
|
||||
column.Name = tableParameter.Alias;
|
||||
end
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ classdef editCode
|
||||
end
|
||||
|
||||
% Формируем новую секцию с нужным текстом
|
||||
% newText = strrep(newText, '\', '\\'); % экранируем для корректной вставки
|
||||
replacement = sprintf('%s START\n%s\n%s END', sectionName, newText, sectionName);
|
||||
|
||||
% Заменяем всю найденную секцию на новую
|
||||
|
||||
120
McuLib/m/init.m
120
McuLib/m/init.m
@@ -1,120 +0,0 @@
|
||||
% Cкрипт для задания параметров модели
|
||||
|
||||
clear;%очищаем рабочее пространство
|
||||
|
||||
%% ПАРАМЕТРЫ МОДЕЛИ
|
||||
|
||||
addpath('MCU_Wrapper');
|
||||
addpath('motor');
|
||||
Ts = 10e-6;%шаг интегрирования
|
||||
Decim = 1;%интервал прореживания
|
||||
DisableScope = {
|
||||
"Idc";
|
||||
"Udc";
|
||||
};
|
||||
|
||||
GED = "23550";
|
||||
% GED = "22220";
|
||||
|
||||
% начальная скорость ГЭД, доля от NmNom
|
||||
w0 = 0;%0.5;%-0.75;%
|
||||
% пусковой момент, о.е.
|
||||
Mst = 0.6;%0.6;
|
||||
|
||||
% разрешаем/запрещаем сбросы/набросы момента нагрузки
|
||||
changingLoadEnable = 0;%1
|
||||
% разрешаем/запрещаем шум в измеренном токе
|
||||
noiseEnable = 0;%1;%
|
||||
% ... мощность шума
|
||||
NP = 0.08;
|
||||
|
||||
|
||||
%% НОМИНАЛЬНЫЕ ВЕЛИЧИНЫ ГЭД
|
||||
% ... мощность на валу, Вт
|
||||
Pnom = 6300e3;
|
||||
% ... линейное напряжение, В (rms)
|
||||
Unom = 3300;
|
||||
% ... механическая скорость, об/мин
|
||||
NmNom = 180;
|
||||
% ... число пар полюсов
|
||||
Pp = 6;
|
||||
% ... коэффициент мощности
|
||||
CosFi = 0.87;
|
||||
% ... КПД
|
||||
Eff = 0.968;
|
||||
% ... приведенный к валу момент инерции, кг*м^2
|
||||
J = 87e3*0.1;
|
||||
|
||||
|
||||
%% РАСЧЕТЫ
|
||||
% разкомментирование всех блоков
|
||||
|
||||
modelName = [bdroot '/Measurements'];
|
||||
blocks = find_system(modelName, ...
|
||||
'IncludeCommented', 'on', ...
|
||||
'FollowLinks', 'on', ...
|
||||
'LookUnderMasks', 'all', ...
|
||||
'BlockType', 'Scope');
|
||||
for i = 1:length(blocks)
|
||||
set_param(blocks{i}, 'Commented', 'off');
|
||||
end
|
||||
% отключение графиков для ускорения смуляции
|
||||
for i = 1:length(DisableScope)
|
||||
set_param([modelName '/'] + DisableScope{i}, 'Commented', 'on');
|
||||
end
|
||||
|
||||
% для упрощения записи
|
||||
SQRT2 = sqrt(2);
|
||||
SQRT3 = sqrt(3);
|
||||
PI2 = pi*2;
|
||||
|
||||
% ... полная мощность, ВА
|
||||
Snom = Pnom/CosFi/Eff;
|
||||
% ... механическая скорость, рад/с
|
||||
WmNom = NmNom/60*PI2;
|
||||
% ... момент на валу, Н*м
|
||||
Mnom = Pnom/WmNom;
|
||||
% ... эл. скорость, рад/с
|
||||
WeNom = WmNom*Pp;
|
||||
% ... эл. скорость, Гц
|
||||
FeNom = WeNom/PI2;
|
||||
% ... потокосцепление статора, Вб
|
||||
PsiNom = Unom*SQRT2/(WeNom*SQRT3);
|
||||
% ... напряжение на входе инвертора, B
|
||||
UdcNom = Unom*SQRT2;
|
||||
% ... ток, А (ampl)
|
||||
Inom = Snom/(Unom*SQRT3)*SQRT2*0.5;%0.5 - т.к. обмоток две
|
||||
|
||||
% схема замещения ГЭД
|
||||
if GED == "22220"
|
||||
GED
|
||||
Rs = 11.8e-3;%Ом
|
||||
Xls = 72.7e-3;%72.7e-3;%Ом
|
||||
Rr = 11.1e-3*2.0;%*0.8;%Ом
|
||||
Xlr = 85.5e-3;%Ом
|
||||
Xm = 2.9322;%2.87;%Ом
|
||||
Fe = 18;%Гц
|
||||
Lls = Xls/(Fe*PI2);%Гн
|
||||
Llr = Xlr/(Fe*PI2);%Гн
|
||||
Lm = Xm/(Fe*PI2);%Гн
|
||||
elseif GED == "23550"
|
||||
GED
|
||||
Rs = 0.0282;%Ом
|
||||
Xls = 0.4016;%Ом
|
||||
Rr = 0.139;%Ом
|
||||
Xlr = 0.2006;%Ом
|
||||
Xm = 5.2796;%Ом
|
||||
Fe = 18.2;%Гц
|
||||
Lls = Xls/(Fe*PI2);%Гн
|
||||
Llr = Xlr/(Fe*PI2);%Гн
|
||||
Lm = Xm/(Fe*PI2);%Гн
|
||||
end
|
||||
|
||||
% ёмкость на входе INU, Ф
|
||||
Cdc = 50e-3;
|
||||
% снаберы в INU
|
||||
Csn = Pnom/(1000*WeNom*Unom^2)/10;%Ф (0.5 - т.к. преобразователей два)
|
||||
Rsn = 2*Ts/Csn*10;%Ом
|
||||
|
||||
% постоянная времени фильтра для тока ГЭД, c
|
||||
Tiac = 30e-6;
|
||||
59
McuLib/m/installTemplates.m
Normal file
59
McuLib/m/installTemplates.m
Normal file
@@ -0,0 +1,59 @@
|
||||
function installTemplates(forceCopy)
|
||||
% installTemplates Копирует содержимое папки templates (включая вложенные папки) из уровня выше McuLib.slx в текущую папку
|
||||
%
|
||||
% installTemplates(forceCopy)
|
||||
%
|
||||
% forceCopy — логический параметр (true/false)
|
||||
% Если true, файлы будут перезаписаны.
|
||||
% Если false или не указан, копирование происходит без перезаписи существующих файлов.
|
||||
|
||||
if nargin < 1
|
||||
forceCopy = false;
|
||||
end
|
||||
|
||||
try
|
||||
libDir = fileparts(which('McuLib.slx')); % папка с McuLib.slx
|
||||
parentDir = fileparts(libDir); % уровень выше
|
||||
templatesDir = fullfile(parentDir, 'templates'); % папка templates
|
||||
|
||||
targetDir = pwd; % текущая папка
|
||||
mcuMask.disp(1, '');
|
||||
if ~exist(templatesDir, 'dir')
|
||||
mcuMask.disp(1, 'Папка шаблонов %s не найдена.', templatesDir);
|
||||
return;
|
||||
end
|
||||
|
||||
% Список всех файлов и папок внутри templates (рекурсивно)
|
||||
entries = dir(fullfile(templatesDir, '**', '*'));
|
||||
|
||||
for k = 1:length(entries)
|
||||
if ~entries(k).isdir
|
||||
% Относительный путь внутри templates
|
||||
relPath = erase(entries(k).folder, [templatesDir filesep]);
|
||||
if startsWith(relPath, filesep)
|
||||
relPath = relPath(2:end); % убрать начальный слеш
|
||||
end
|
||||
|
||||
srcFile = fullfile(entries(k).folder, entries(k).name);
|
||||
destFolder = fullfile(targetDir, relPath);
|
||||
destFile = fullfile(destFolder, entries(k).name);
|
||||
|
||||
if ~exist(destFolder, 'dir')
|
||||
mkdir(destFolder);
|
||||
end
|
||||
|
||||
if forceCopy || ~exist(destFile, 'file')
|
||||
copyfile(srcFile, destFile);
|
||||
mcuMask.disp(0, 'Скопирован файл: %s\n', fullfile(relPath, entries(k).name));
|
||||
else
|
||||
% mcuMask.disp(0, 'Файл уже существует и не перезаписывается: %s\n', fullfile(relPath, entries(k).name));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mcuMask.disp(0, ['Шаблоны успешно скопированы в ', targetDir]);
|
||||
|
||||
catch ME
|
||||
mcuMask.disp(0, 'Ошибка при копировании шаблонов: %s', ME.message);
|
||||
end
|
||||
end
|
||||
@@ -10,6 +10,8 @@ classdef mcuMask
|
||||
blk = gcbh;
|
||||
% Получаем объект маски текущего блока
|
||||
mask = Simulink.Mask.get(gcb);
|
||||
set_param(blk,"MaskSelfModifiable","on")
|
||||
set_param(blk, 'LinkStatus', 'none');
|
||||
% mcuMask.disp(1,'');
|
||||
try
|
||||
% Проверка наличия findjobj
|
||||
@@ -17,8 +19,6 @@ classdef mcuMask
|
||||
catch
|
||||
findjobjAvailable = false;
|
||||
end
|
||||
% Получаем объект маски текущего блока
|
||||
mask = Simulink.Mask.get(gcb);
|
||||
% Имя checkbox-параметра (укажите точное имя из маски)
|
||||
checkboxParamName = 'extConsol'; % пример
|
||||
findjobjLinkName = 'findjobj_link'; % пример
|
||||
@@ -46,7 +46,7 @@ classdef mcuMask
|
||||
table_names = {'srcTable', 'incTable'};
|
||||
for k = 1:numel(table_names)
|
||||
table_name = table_names{k};
|
||||
% customtable.format(table_name);
|
||||
customtable.format(table_name);
|
||||
end
|
||||
% запись описания блока
|
||||
textDesc = ['Блок для настройки параметров симуляции микроконтроллера. ' newline ...
|
||||
@@ -119,42 +119,37 @@ classdef mcuMask
|
||||
end
|
||||
|
||||
function wrapperPath_add(callbackContext)
|
||||
block = gcb;
|
||||
mask = Simulink.Mask.get(block);
|
||||
% Открываем окно выбора папки
|
||||
folderPath = uigetdir('', 'Выберите папку');
|
||||
% Проверка на отмену
|
||||
if isequal(folderPath, 0)
|
||||
return;
|
||||
end
|
||||
% Установка значения параметра маски
|
||||
rel = mcuMask.absoluteToRelativePath(folderPath);
|
||||
param = mask.getParameter('wrapperPath');
|
||||
param.Value = rel;
|
||||
|
||||
mcuPath.addPath('wrapperPath');
|
||||
end
|
||||
|
||||
function appWrapperPath_add(callbackContext)
|
||||
mcuPath.addPath('appWrapperPath');
|
||||
end
|
||||
%% USER WRAPPER CODE
|
||||
|
||||
function wrapperFunc(callbackContext)
|
||||
function appWrapperFunc(callbackContext)
|
||||
block = gcb;
|
||||
% Получаем имя функции и путь к файлам
|
||||
[filename, section, tool, example]= mcuMask.getWrapperUserFile(block);
|
||||
mcuMask.tool(tool, example);
|
||||
|
||||
% Загружаем содержимое файла
|
||||
set_param(block, 'wrapperCode', '');
|
||||
code = fileread(filename);
|
||||
code = regexprep(code, '\r\n?', '\n'); % нормализуем окончания строк
|
||||
set_param(block, 'appWrapperCode', '');
|
||||
try
|
||||
code = fileread(filename);
|
||||
code = regexprep(code, '\r\n?', '\n'); % нормализуем окончания строк
|
||||
|
||||
includesText = editCode.extractSection(code, section);
|
||||
set_param(block, 'wrapperCode', includesText);
|
||||
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 saveWrapperCode(callbackContext)
|
||||
function saveAppWrapperCode(callbackContext)
|
||||
block = gcb;
|
||||
|
||||
% Получаем имя функции и путь к файлам
|
||||
@@ -164,15 +159,16 @@ classdef mcuMask
|
||||
return;
|
||||
end
|
||||
|
||||
sel = get_param(block, 'wrapperFunc');
|
||||
basePath = get_param(block, 'wrapperPath');
|
||||
sel = get_param(block, 'appWrapperFunc');
|
||||
basePath = get_param(block, 'appWrapperPath');
|
||||
if isempty(basePath)
|
||||
errordlg('Не указан путь к файлам обёртки (wrapperPath).');
|
||||
return;
|
||||
end
|
||||
newBody = get_param(block, 'wrapperCode');
|
||||
newBody = get_param(block, 'appWrapperCode');
|
||||
code = fileread(filename);
|
||||
code = regexprep(code, '\r\n?', '\n');
|
||||
newBody = strrep(newBody, '\', '\\');
|
||||
code = editCode.insertSection(code, section, newBody);
|
||||
% else
|
||||
% % Обновляем тело функции
|
||||
@@ -189,11 +185,11 @@ classdef mcuMask
|
||||
mcuMask.disp(1, ['Обновлено: ' sel]);
|
||||
end
|
||||
|
||||
function openWrapperCode(callbackContext)
|
||||
function openAppWrapperCode(callbackContext)
|
||||
block = gcb;
|
||||
|
||||
% Получаем имя функции и путь к файлам
|
||||
filename = mcuMask.getAbsolutePath(mcuMask.getWrapperUserFile(block));
|
||||
filename = mcuPath.getAbsolutePath(mcuMask.getWrapperUserFile(block));
|
||||
if exist(filename, 'file') == 2
|
||||
% Формируем команду без кавычек
|
||||
cmd = sprintf('rundll32.exe shell32.dll,OpenAs_RunDLL %s', filename);
|
||||
@@ -216,83 +212,27 @@ classdef mcuMask
|
||||
end
|
||||
|
||||
function btnAddSrc(callbackContext)
|
||||
blockHandle = gcb;
|
||||
% Открываем проводник для выбора файлов
|
||||
[files, pathstr] = uigetfile({ ...
|
||||
'*.c;*.cpp', 'Исходные файлы (*.c, *.cpp)'; ...
|
||||
'*.obj;*.lib', 'Библиотеки (*.obj, *.lib)'; ...
|
||||
'*.*', 'Все файлы (*.*)'}, ...
|
||||
'Выберите файлы', ...
|
||||
'MultiSelect', 'on');
|
||||
|
||||
if isequal(files, 0)
|
||||
return; % Отмена выбора
|
||||
end
|
||||
if ischar(files)
|
||||
files = {files}; % Один файл — в cell
|
||||
end
|
||||
% Парсим строку в cell-массив
|
||||
oldTable = customtable.parse('srcTable');
|
||||
|
||||
% Добавляем новые пути, проверяя уникальность
|
||||
for i = 1:numel(files)
|
||||
fullpath = fullfile(pathstr, files{i});
|
||||
rel = mcuMask.absoluteToRelativePath(fullpath);
|
||||
if ~any(strcmp(rel, oldTable))
|
||||
oldTable{end+1, 1} = rel;
|
||||
end
|
||||
end
|
||||
|
||||
% Парсим строку в cell-массив
|
||||
customtable.collect('srcTable', oldTable);
|
||||
|
||||
mcuPath.addSourceFileTable('srcTable', 'Выберите исходные файлы');
|
||||
end
|
||||
|
||||
function btnAddInc(callbackContext)
|
||||
blockHandle = gcb;
|
||||
% Открываем проводник для выбора папок
|
||||
pathstr = uigetdir(pwd, 'Выберите папку с заголовочными файлами');
|
||||
if isequal(pathstr, 0)
|
||||
return; % Отмена выбора
|
||||
end
|
||||
% Парсим таблицу
|
||||
oldTable = customtable.parse('incTable');
|
||||
|
||||
rel = mcuMask.absoluteToRelativePath(pathstr);
|
||||
|
||||
% Проверяем наличие пути
|
||||
if ~any(strcmp(rel, oldTable))
|
||||
oldTable{end+1, 1} = rel;
|
||||
end
|
||||
|
||||
% Собираем таблицу
|
||||
customtable.collect('incTable', oldTable);
|
||||
mcuPath.addPathTable('incTable', 'Выберите папку с заголовочными файлами');
|
||||
end
|
||||
|
||||
%% PERIPH CONFIG
|
||||
|
||||
function periphPath_add(callbackContext)
|
||||
block = gcbh;
|
||||
mask = Simulink.Mask.get(block);
|
||||
[file, path] = uigetfile({'*.*','Все файлы (*.*)'}, 'Выберите файл');
|
||||
if isequal(file, 0) || isequal(path, 0)
|
||||
% Отмена выбора — ничего не делаем
|
||||
return;
|
||||
end
|
||||
fullFilePath = fullfile(path, file);
|
||||
rel = mcuMask.absoluteToRelativePath(fullFilePath);
|
||||
param = mask.getParameter('periphPath');
|
||||
param.Value = rel;
|
||||
mcuPath.addAnyFile('periphPath');
|
||||
end
|
||||
|
||||
%% COMPILE
|
||||
function compile(callbackContext)
|
||||
addpath('MCU_Wrapper');
|
||||
mexing(1);
|
||||
compiler.compile();
|
||||
end
|
||||
|
||||
|
||||
function updateModel(callbackContext)
|
||||
addpath('MCU_Wrapper');
|
||||
addpath(mcuPath.get('wrapperPath'));
|
||||
res = mexing(1);
|
||||
if res ~= 0
|
||||
return;
|
||||
@@ -309,16 +249,20 @@ classdef mcuMask
|
||||
web('https://www.mathworks.com/matlabcentral/fileexchange/14317-findjobj-find-java-handles-of-matlab-graphic-objects');
|
||||
end
|
||||
|
||||
function set_name()
|
||||
function set_name(callbackContext)
|
||||
block = gcb;
|
||||
% Получаем параметр имени S-Function из маски блока
|
||||
newName = get_param(block, 'sfuncName');
|
||||
newName = mcuMask.get_name();
|
||||
|
||||
% Путь к файлу, в котором надо заменить строку
|
||||
cFilePath = fullfile(pwd, './MCU_Wrapper/MCU.c'); % <-- укажи правильный путь
|
||||
cFilePath = fullfile(pwd, mcuPath.get('wrapperPath'), 'MCU.c'); % <-- укажи правильный путь
|
||||
|
||||
% Считаем файл в память
|
||||
fileText = fileread(cFilePath);
|
||||
try
|
||||
fileText = fileread(cFilePath);
|
||||
catch
|
||||
return;
|
||||
end
|
||||
|
||||
% Регулярное выражение для поиска строки с define
|
||||
% Заменим строку вида: #define S_FUNCTION_NAME old_name
|
||||
@@ -336,10 +280,8 @@ classdef mcuMask
|
||||
error('Не удалось открыть файл для записи.');
|
||||
end
|
||||
fwrite(fid, updatedText);
|
||||
fclose(fid);
|
||||
|
||||
fclose(fid);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -347,8 +289,8 @@ classdef mcuMask
|
||||
methods(Static, Access = private)
|
||||
|
||||
function [filename, section, tool, example] = getWrapperUserFile(block)
|
||||
sel = get_param(block, 'wrapperFunc');
|
||||
basePath = get_param(block, 'wrapperPath');
|
||||
sel = get_param(block, 'appWrapperFunc');
|
||||
basePath = mcuPath.get('appWrapperPath');
|
||||
if isempty(basePath)
|
||||
errordlg('Не указан путь к файлам обёртки (wrapperPath).');
|
||||
return;
|
||||
@@ -445,81 +387,13 @@ classdef mcuMask
|
||||
mcuMask.disp(clear_flag, '');
|
||||
end
|
||||
|
||||
|
||||
function absPath = getAbsolutePath(relPath)
|
||||
% relativeToAbsolutePath — преобразует относительный путь в абсолютный.
|
||||
%
|
||||
% Если путь уже абсолютный — возвращается он же, приведённый к канонической форме.
|
||||
% Если путь относительный — преобразуется относительно текущей директории.
|
||||
|
||||
% Проверка: абсолютный ли путь
|
||||
if ispc
|
||||
isAbsolute = ~isempty(regexp(relPath, '^[a-zA-Z]:[\\/]', 'once')) || startsWith(relPath, '\\');
|
||||
else
|
||||
isAbsolute = startsWith(relPath, '/');
|
||||
end
|
||||
|
||||
if isAbsolute
|
||||
% Канонизируем абсолютный путь (убираем ./, ../ и т.п.)
|
||||
absPath = char(java.io.File(relPath).getCanonicalPath());
|
||||
else
|
||||
% Строим абсолютный путь от текущей директории
|
||||
cwd = pwd;
|
||||
combined = fullfile(cwd, relPath);
|
||||
absPath = char(java.io.File(combined).getCanonicalPath());
|
||||
end
|
||||
function name = get_name()
|
||||
block = gcb;
|
||||
% Получаем параметр имени S-Function из маски блока
|
||||
name = get_param(block, 'sfuncName');
|
||||
end
|
||||
|
||||
|
||||
|
||||
function rel = absoluteToRelativePath(pathstr)
|
||||
% absoluteToRelativePath — преобразует абсолютный путь в относительный от текущей директории.
|
||||
%
|
||||
% Если путь находится в текущей директории или вложенной в неё — добавляется префикс './'
|
||||
% Если выше — формируются переходы '..'
|
||||
% Если путь совпадает с текущей директорией — возвращается '.'
|
||||
|
||||
% Получаем текущую рабочую директорию
|
||||
cwd = pwd;
|
||||
|
||||
% Преобразуем пути в канонические абсолютные пути
|
||||
fullpath = char(java.io.File(pathstr).getCanonicalPath());
|
||||
cwd = char(java.io.File(cwd).getCanonicalPath());
|
||||
|
||||
% Разбиваем пути на части
|
||||
targetParts = strsplit(fullpath, filesep);
|
||||
baseParts = strsplit(cwd, filesep);
|
||||
|
||||
% Находим длину общего префикса
|
||||
j = 1;
|
||||
while j <= min(length(targetParts), length(baseParts)) && strcmpi(targetParts{j}, baseParts{j})
|
||||
j = j + 1;
|
||||
end
|
||||
|
||||
% Формируем количество подъемов ".." из cwd
|
||||
numUps = length(baseParts) - (j - 1);
|
||||
ups = repmat({'..'}, 1, numUps);
|
||||
|
||||
% Оставшаяся часть пути после общего префикса
|
||||
rest = targetParts(j:end);
|
||||
|
||||
% Объединяем для получения относительного пути
|
||||
relParts = [ups, rest];
|
||||
rel = fullfile(relParts{:});
|
||||
|
||||
% Если путь пустой — это текущая директория
|
||||
if isempty(rel)
|
||||
rel = '.';
|
||||
end
|
||||
|
||||
% Если путь не содержит ".." и начинается внутри текущей директории — добавим './'
|
||||
if ~isempty(rest) && isempty(ups)
|
||||
rel = fullfile('.', rel);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function checkbox_state = read_checkbox(checkboxName)
|
||||
maskValues = get_param(gcbh, 'MaskValues');
|
||||
paramNames = get_param(gcbh, 'MaskNames');
|
||||
@@ -579,15 +453,7 @@ classdef mcuMask
|
||||
end
|
||||
end
|
||||
|
||||
function res = ternary(cond, valTrue, valFalse)
|
||||
if cond
|
||||
res = valTrue;
|
||||
else
|
||||
res = valFalse;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function tool(text, example)
|
||||
% Устанавливает заданный текст в параметр Text Area 'toolText' через объект маски
|
||||
|
||||
|
||||
168
McuLib/m/mcuPath.m
Normal file
168
McuLib/m/mcuPath.m
Normal file
@@ -0,0 +1,168 @@
|
||||
classdef mcuPath
|
||||
methods(Static)
|
||||
|
||||
|
||||
|
||||
function path = get(paramName)
|
||||
blockPath = gcb;
|
||||
path = get_param(blockPath, paramName);
|
||||
end
|
||||
|
||||
|
||||
function addSourceFileTable(targetParamName, message)
|
||||
% Открываем проводник для выбора файлов
|
||||
[files, pathstr] = uigetfile({ ...
|
||||
'*.c;*.cpp', 'Исходные файлы (*.c, *.cpp)'; ...
|
||||
'*.obj;*.lib', 'Библиотеки (*.obj, *.lib)'; ...
|
||||
'*.*', 'Все файлы (*.*)'}, ...
|
||||
message, ...
|
||||
'MultiSelect', 'on');
|
||||
|
||||
if isequal(files, 0)
|
||||
return; % Отмена выбора
|
||||
end
|
||||
if ischar(files)
|
||||
files = {files}; % Один файл — в cell
|
||||
end
|
||||
% Парсим строку в cell-массив
|
||||
oldTable = customtable.parse(targetParamName);
|
||||
|
||||
% Добавляем новые пути, проверяя уникальность
|
||||
for i = 1:numel(files)
|
||||
fullpath = fullfile(pathstr, files{i});
|
||||
rel = mcuPath.absoluteToRelativePath(fullpath);
|
||||
if ~any(strcmp(rel, oldTable))
|
||||
oldTable{end+1, 1} = rel;
|
||||
end
|
||||
end
|
||||
|
||||
% Парсим строку в cell-массив
|
||||
customtable.collect(targetParamName, oldTable);
|
||||
|
||||
end
|
||||
|
||||
function addPathTable(targetParamName, message)
|
||||
% Открываем проводник для выбора папок
|
||||
pathstr = uigetdir(pwd, message);
|
||||
if isequal(pathstr, 0)
|
||||
return; % Отмена выбора
|
||||
end
|
||||
% Парсим таблицу
|
||||
oldTable = customtable.parse(targetParamName);
|
||||
|
||||
rel = mcuPath.absoluteToRelativePath(pathstr);
|
||||
|
||||
% Проверяем наличие пути
|
||||
if ~any(strcmp(rel, oldTable))
|
||||
oldTable{end+1, 1} = rel;
|
||||
end
|
||||
|
||||
% Собираем таблицу
|
||||
customtable.collect(targetParamName, oldTable);
|
||||
end
|
||||
|
||||
|
||||
function addPath(targetParamName, message)
|
||||
block = gcb;
|
||||
mask = Simulink.Mask.get(block);
|
||||
% Открываем окно выбора папки
|
||||
folderPath = uigetdir('', 'Выберите папку');
|
||||
% Проверка на отмену
|
||||
if isequal(folderPath, 0)
|
||||
return;
|
||||
end
|
||||
% Установка значения параметра маски
|
||||
rel = mcuPath.absoluteToRelativePath(folderPath);
|
||||
param = mask.getParameter(targetParamName);
|
||||
param.Value = rel;
|
||||
end
|
||||
|
||||
function addAnyFile(targetParamName, message)
|
||||
block = gcbh;
|
||||
mask = Simulink.Mask.get(block);
|
||||
[file, path] = uigetfile({'*.*','Все файлы (*.*)'}, 'Выберите файл');
|
||||
if isequal(file, 0) || isequal(path, 0)
|
||||
% Отмена выбора — ничего не делаем
|
||||
return;
|
||||
end
|
||||
fullFilePath = fullfile(path, file);
|
||||
rel = mcuPath.absoluteToRelativePath(fullFilePath);
|
||||
param = mask.getParameter(targetParamName);
|
||||
param.Value = rel;
|
||||
end
|
||||
|
||||
function absPath = getAbsolutePath(relPath)
|
||||
% relativeToAbsolutePath — преобразует относительный путь в абсолютный.
|
||||
%
|
||||
% Если путь уже абсолютный — возвращается он же, приведённый к канонической форме.
|
||||
% Если путь относительный — преобразуется относительно текущей директории.
|
||||
|
||||
% Проверка: абсолютный ли путь
|
||||
if ispc
|
||||
isAbsolute = ~isempty(regexp(relPath, '^[a-zA-Z]:[\\/]', 'once')) || startsWith(relPath, '\\');
|
||||
else
|
||||
isAbsolute = startsWith(relPath, '/');
|
||||
end
|
||||
|
||||
if isAbsolute
|
||||
% Канонизируем абсолютный путь (убираем ./, ../ и т.п.)
|
||||
absPath = char(java.io.File(relPath).getCanonicalPath());
|
||||
else
|
||||
% Строим абсолютный путь от текущей директории
|
||||
cwd = pwd;
|
||||
combined = fullfile(cwd, relPath);
|
||||
absPath = char(java.io.File(combined).getCanonicalPath());
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function rel = absoluteToRelativePath(pathstr)
|
||||
% absoluteToRelativePath — преобразует абсолютный путь в относительный от текущей директории.
|
||||
%
|
||||
% Если путь находится в текущей директории или вложенной в неё — добавляется префикс './'
|
||||
% Если выше — формируются переходы '..'
|
||||
% Если путь совпадает с текущей директорией — возвращается '.'
|
||||
|
||||
% Получаем текущую рабочую директорию
|
||||
cwd = pwd;
|
||||
|
||||
% Преобразуем пути в канонические абсолютные пути
|
||||
fullpath = char(java.io.File(pathstr).getCanonicalPath());
|
||||
cwd = char(java.io.File(cwd).getCanonicalPath());
|
||||
|
||||
% Разбиваем пути на части
|
||||
targetParts = strsplit(fullpath, filesep);
|
||||
baseParts = strsplit(cwd, filesep);
|
||||
|
||||
% Находим длину общего префикса
|
||||
j = 1;
|
||||
while j <= min(length(targetParts), length(baseParts)) && strcmpi(targetParts{j}, baseParts{j})
|
||||
j = j + 1;
|
||||
end
|
||||
|
||||
% Формируем количество подъемов ".." из cwd
|
||||
numUps = length(baseParts) - (j - 1);
|
||||
ups = repmat({'..'}, 1, numUps);
|
||||
|
||||
% Оставшаяся часть пути после общего префикса
|
||||
rest = targetParts(j:end);
|
||||
|
||||
% Объединяем для получения относительного пути
|
||||
relParts = [ups, rest];
|
||||
rel = fullfile(relParts{:});
|
||||
|
||||
% Если путь пустой — это текущая директория
|
||||
if isempty(rel)
|
||||
rel = '.';
|
||||
end
|
||||
|
||||
% Если путь не содержит ".." и начинается внутри текущей директории — добавим './'
|
||||
if ~isempty(rest) && isempty(ups)
|
||||
rel = fullfile('.', rel);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
@@ -5,8 +5,8 @@ classdef mcuPorts
|
||||
function write()
|
||||
block = gcb;
|
||||
mask = Simulink.Mask.get(block);
|
||||
hPath = fullfile('.\MCU_Wrapper', 'mcu_wrapper_conf.h');
|
||||
cPath = fullfile('.\MCU_Wrapper', 'mcu_wrapper.c');
|
||||
hPath = fullfile(mcuPath.get('wrapperPath'), 'mcu_wrapper_conf.h');
|
||||
cPath = fullfile(mcuPath.get('wrapperPath'), 'mcu_wrapper.c');
|
||||
mcuPorts.defaultUnused();
|
||||
%% CREATE
|
||||
prefixNumb = 'IN';
|
||||
@@ -190,10 +190,10 @@ classdef mcuPorts
|
||||
|
||||
for i = 1:n
|
||||
if i == 1
|
||||
lines{end+1} = '#define OFFSET_ARRAY_1 0';
|
||||
lines{end+1} = sprintf('#define OFFSET_%s_ARRAY_1 0', upperPrefix);
|
||||
else
|
||||
lines{end+1} = sprintf('#define OFFSET_ARRAY_%d (OFFSET_ARRAY_%d + %s_PORT_%d_WIDTH)', ...
|
||||
i, i - 1, upper(portPrefixes{i - 1}), i - 1);
|
||||
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);
|
||||
@@ -251,7 +251,7 @@ classdef mcuPorts
|
||||
if i == n
|
||||
comma = '';
|
||||
end
|
||||
lines{end+1} = sprintf(' OFFSET_ARRAY_%d%s', i, comma);
|
||||
lines{end+1} = sprintf(' OFFSET_%s_ARRAY_%d%s', upperPrefix, i, comma);
|
||||
end
|
||||
lines{end+1} = '};';
|
||||
lines{end+1} = '';
|
||||
|
||||
@@ -4,12 +4,11 @@ function res = mexing(compile_mode)
|
||||
Ts = 0.00001;
|
||||
|
||||
if compile_mode == 1
|
||||
delete("*.mexw64")
|
||||
delete("*.mexw64.pdb")
|
||||
delete(".\MCU_Wrapper\Outputs\*.*");
|
||||
delete('*.mexw64')
|
||||
delete('*.mexw64.pdb')
|
||||
delete([mcuPath.get('wrapperPath'), '\Outputs\*.*']);
|
||||
set_param(gcb, 'consoleOutput', '');
|
||||
% Порты S-Function
|
||||
mcuPorts.write();
|
||||
compiler.updateRunBat();
|
||||
% Дефайны
|
||||
definesUserArg = parseDefinesMaskText();
|
||||
definesWrapperConfigArg = buildWrapperDefinesString();
|
||||
@@ -30,8 +29,11 @@ function res = mexing(compile_mode)
|
||||
|
||||
[includesArg, codeArg] = make_mex_arguments('incTable', 'srcTable');
|
||||
|
||||
Name = mcuMask.get_name();
|
||||
|
||||
% Вызов батника с двумя параметрами: includes и code
|
||||
cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" "%s" %s %s', includesArg, codeArg, definesUserArg, definesConfigArg, modeArg, echoArg);
|
||||
run_bat_mex_path = fullfile(mcuPath.get('wrapperPath'), 'run_mex.bat');
|
||||
cmd = sprintf('%s %s "%s" "%s" "%s" "%s" %s %s', run_bat_mex_path, Name, includesArg, codeArg, definesUserArg, definesConfigArg, modeArg, echoArg);
|
||||
|
||||
if mcuMask.read_checkbox('extConsol')
|
||||
cmdout = runBatAndShowOutput(cmd);
|
||||
@@ -68,9 +70,6 @@ function res = mexing(compile_mode)
|
||||
config = periphConfig.update_config(blockPath, config);
|
||||
periphConfig.write_config(config);
|
||||
periphConfig.update(blockPath, config);
|
||||
% Порты S-Function
|
||||
mcuPorts.write();
|
||||
% set_param(gcb, 'consoleOutput', 'Peripheral configuration file loaded. Re-open Block Parameters');
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ classdef periphConfig
|
||||
% Проверяем, была ли маска открыта
|
||||
% wasOpen = isMaskDialogOpen(blockPath);
|
||||
mask = Simulink.Mask.get(blockPath);
|
||||
periphPath = get_param(blockPath, 'periphPath');
|
||||
periphPath = mcuPath.get('periphPath');
|
||||
[periphPath, ~, ~] = fileparts(periphPath);
|
||||
|
||||
tableNames = {'incTable', 'srcTable'};
|
||||
@@ -91,7 +91,7 @@ classdef periphConfig
|
||||
for i = 1:numel(periphs)
|
||||
periph = periphs{i};
|
||||
|
||||
% Пропускаем Code и UserCode, они уже обработаны
|
||||
% Пропускаем Code и UserCode
|
||||
if strcmp(periph, 'Code') || strcmp(periph, 'UserCode')
|
||||
continue;
|
||||
end
|
||||
@@ -165,86 +165,24 @@ classdef periphConfig
|
||||
fwrite(fid, jsonText, 'char');
|
||||
fclose(fid);
|
||||
end
|
||||
|
||||
function clear_all_from_container(mask, containerName)
|
||||
% allControls = mask.getDialogControls();
|
||||
container = mask.getDialogControl(containerName);
|
||||
if isempty(container)
|
||||
warning('Контейнер "%s" не найден.', containerName);
|
||||
return;
|
||||
end
|
||||
|
||||
% Рекурсивно собрать все параметры (не вкладки)
|
||||
paramsToDelete = mcuMask.collect_all_parameters(container);
|
||||
|
||||
% Удаляем все параметры
|
||||
for i = 1:numel(paramsToDelete)
|
||||
try
|
||||
mask.removeParameter(paramsToDelete{i});
|
||||
catch
|
||||
warning('Не удалось удалить параметр %s', paramsToDelete{i});
|
||||
end
|
||||
end
|
||||
|
||||
% Рекурсивно удалить все вкладки внутри контейнера
|
||||
mcuMask.delete_all_tabs(mask, container);
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
methods(Static, Access=private)
|
||||
|
||||
|
||||
function res = addCodeConfig(codeConfig, periphPath)
|
||||
% Возвращает 0 при успехе, 1 при ошибке
|
||||
try
|
||||
% Источники
|
||||
srcList = {};
|
||||
if isfield(codeConfig, 'Sources') && isfield(codeConfig.Sources, 'Options')
|
||||
srcFiles = codeConfig.Sources.Options;
|
||||
for i = 1:numel(srcFiles)
|
||||
fullPath = fullfile(periphPath, srcFiles{i});
|
||||
srcList{end+1} = [strrep(fullPath, '\', '\\')];
|
||||
end
|
||||
end
|
||||
|
||||
% Формируем srcText с переносами строк и ^
|
||||
srcText = '';
|
||||
for i = 1:numel(srcList)
|
||||
if i < numel(srcList)
|
||||
srcText = [srcText srcList{i} '^' newline ' '];
|
||||
else
|
||||
srcText = [srcText srcList{i}];
|
||||
end
|
||||
end
|
||||
|
||||
% Инклуды
|
||||
incList = {};
|
||||
if isfield(codeConfig, 'Includes') && isfield(codeConfig.Includes, 'Options')
|
||||
incPaths = codeConfig.Includes.Options;
|
||||
for i = 1:numel(incPaths)
|
||||
fullPath = fullfile(periphPath, incPaths{i});
|
||||
incList{end+1} = ['-I"' strrep(fullPath, '\', '\\') '"'];
|
||||
end
|
||||
end
|
||||
|
||||
% Формируем incText с переносами строк и ^
|
||||
incText = '';
|
||||
for i = 1:numel(incList)
|
||||
if i == 1 && numel(incList) ~= 1
|
||||
incText = [incText incList{i} '^' newline];
|
||||
elseif i < numel(incList)
|
||||
incText = [incText ' ' incList{i} '^' newline];
|
||||
else
|
||||
incText = [incText ' ' incList{i}];
|
||||
end
|
||||
end
|
||||
|
||||
% Добавляем префиксы
|
||||
srcText = ['set code_PERIPH' '=' srcText];
|
||||
incText = ['set includes_PERIPH' '=' incText];
|
||||
% Формируем строки
|
||||
srcText = compiler.createSourcesBat('code_PERIPH', codeConfig.Sources.Options, periphPath);
|
||||
incText = compiler.createIncludesBat('includes_PERIPH', codeConfig.Includes.Options, periphPath);
|
||||
|
||||
% Записываем результат
|
||||
res = periphConfig.updateRunMexBat(srcText, incText); % Всё прошло успешно
|
||||
res = compiler.updateRunMexBat(srcText, incText, ':: PERIPH BAT'); % Всё прошло успешно
|
||||
catch
|
||||
% В случае ошибки просто возвращаем 1
|
||||
res = 1;
|
||||
@@ -289,7 +227,7 @@ classdef periphConfig
|
||||
%
|
||||
% Возвращает:
|
||||
% res - 0 при успехе, 1 при ошибке
|
||||
wrapPath = fullfile('.\MCU_Wrapper', 'mcu_wrapper.c');
|
||||
wrapPath = fullfile(mcuPath.get('wrapperPath'), 'mcu_wrapper.c');
|
||||
res = 1;
|
||||
try
|
||||
code = fileread(wrapPath);
|
||||
@@ -314,36 +252,6 @@ classdef periphConfig
|
||||
|
||||
|
||||
|
||||
function res = updateRunMexBat(srcText, incText)
|
||||
% Входные параметры:
|
||||
% srcText - текст для записи set code_...
|
||||
% incText - текст для записи set includes_...
|
||||
%
|
||||
% Возвращает:
|
||||
% res - 0 при успехе, 1 при ошибке
|
||||
periphBat = [srcText '\n\n' incText];
|
||||
batPath = fullfile('.\MCU_Wrapper', 'run_mex.bat');
|
||||
res = 1;
|
||||
try
|
||||
code = fileread(batPath);
|
||||
code = regexprep(code, '\r\n?', '\n');
|
||||
|
||||
% Записываем строки srcText и incText с переносами строк
|
||||
code = editCode.insertSection(code, ':: PERIPH BAT', periphBat);
|
||||
|
||||
fid = fopen(batPath, 'w', 'n', 'UTF-8');
|
||||
if fid == -1
|
||||
error('Не удалось открыть файл для записи');
|
||||
end
|
||||
fwrite(fid, code);
|
||||
fclose(fid);
|
||||
res = 1;
|
||||
catch ME
|
||||
mcuMask.disp(0, '\nОшибка: неудачная запись в файл при записи файла: %s', ME.message);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function addDefineConfig(mask, containerName, periphName, defPrompt, def)
|
||||
% mask — объект маски Simulink.Mask.get(blockPath)
|
||||
@@ -371,6 +279,8 @@ classdef periphConfig
|
||||
paramType = 'checkbox';
|
||||
case 'edit'
|
||||
paramType = 'edit';
|
||||
case 'popup'
|
||||
paramType = 'popup';
|
||||
otherwise
|
||||
% Игнорируем остальные типы
|
||||
return;
|
||||
@@ -378,28 +288,46 @@ classdef periphConfig
|
||||
|
||||
paramName = matlab.lang.makeValidName(defPrompt);
|
||||
|
||||
% Преобразуем значение Default в строку для Value
|
||||
val = def.Default;
|
||||
if islogical(val)
|
||||
valStr = mcuMask.ternary(val, 'on', 'off');
|
||||
elseif isnumeric(val)
|
||||
valStr = num2str(val);
|
||||
elseif ischar(val)
|
||||
valStr = val;
|
||||
% Получаем значение
|
||||
if strcmp(paramType, 'popup')
|
||||
if isfield(def, 'Def') && iscell(def.Def) && ~isempty(def.Def)
|
||||
choices = def.Def;
|
||||
valStr = ''; % по умолчанию — ничего
|
||||
else
|
||||
warning('Popout параметр "%s" не содержит допустимого списка в Def.', defPrompt);
|
||||
return;
|
||||
end
|
||||
else
|
||||
error('Unsupported default value type for %s.%s', periphName, defPrompt);
|
||||
val = def.Default;
|
||||
if islogical(val)
|
||||
valStr = periphConfig.ternary(val, 'on', 'off');
|
||||
elseif isnumeric(val)
|
||||
valStr = num2str(val);
|
||||
elseif ischar(val)
|
||||
valStr = val;
|
||||
else
|
||||
error('Unsupported default value type for %s.%s', periphName, defPrompt);
|
||||
end
|
||||
end
|
||||
|
||||
% Добавляем параметр в маску
|
||||
param = mask.addParameter( ...
|
||||
'Type', paramType, ...
|
||||
'Prompt', def.Prompt, ...
|
||||
'Name', paramName, ...
|
||||
'Value', valStr, ...
|
||||
'Container', periphName ...
|
||||
);
|
||||
if strcmp(paramType, 'popup')
|
||||
param = mask.addParameter( ...
|
||||
'Type', paramType, ...
|
||||
'Prompt', def.Prompt, ...
|
||||
'Name', paramName, ...
|
||||
'Container', periphName ...
|
||||
);
|
||||
else
|
||||
param = mask.addParameter( ...
|
||||
'Type', paramType, ...
|
||||
'Prompt', def.Prompt, ...
|
||||
'Name', paramName, ...
|
||||
'Value', valStr, ...
|
||||
'Container', periphName ...
|
||||
);
|
||||
end
|
||||
|
||||
param.Alias = def.Def;
|
||||
param.Evaluate = 'off';
|
||||
|
||||
if def.NewRow
|
||||
@@ -407,8 +335,46 @@ classdef periphConfig
|
||||
else
|
||||
param.DialogControl.Row = 'current';
|
||||
end
|
||||
|
||||
if strcmp(paramType, 'popup')
|
||||
param.TypeOptions = def.Def;
|
||||
else
|
||||
param.Alias = def.Def;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function clear_all_from_container(mask, containerName)
|
||||
% allControls = mask.getDialogControls();
|
||||
container = mask.getDialogControl(containerName);
|
||||
if isempty(container)
|
||||
warning('Контейнер "%s" не найден.', containerName);
|
||||
return;
|
||||
end
|
||||
|
||||
% Рекурсивно собрать все параметры (не вкладки)
|
||||
paramsToDelete = mcuMask.collect_all_parameters(container);
|
||||
|
||||
% Удаляем все параметры
|
||||
for i = 1:numel(paramsToDelete)
|
||||
try
|
||||
mask.removeParameter(paramsToDelete{i});
|
||||
catch
|
||||
warning('Не удалось удалить параметр %s', paramsToDelete{i});
|
||||
end
|
||||
end
|
||||
|
||||
% Рекурсивно удалить все вкладки внутри контейнера
|
||||
mcuMask.delete_all_tabs(mask, container);
|
||||
end
|
||||
|
||||
function res = ternary(cond, valTrue, valFalse)
|
||||
if cond
|
||||
res = valTrue;
|
||||
else
|
||||
res = valFalse;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -115,7 +115,7 @@ static void mdlInitializeSizes(SimStruct* S)
|
||||
for (int i = 0; i < IN_PORT_NUMB; i++)
|
||||
{
|
||||
ssSetInputPortWidth(S, i, inLengths[i]);
|
||||
ssSetInputPortDirectFeedThrough(S, i, 0); // или 1, если нужно
|
||||
ssSetInputPortDirectFeedThrough(S, i, 0);
|
||||
ssSetInputPortRequiredContiguous(S, i, 1);
|
||||
}
|
||||
|
||||
@@ -212,13 +212,13 @@ void SIM_writeOutputs(SimStruct* S)
|
||||
int global_index;
|
||||
|
||||
//-------------WRITTING OUTPUT--------------
|
||||
for (int j = 0; j < OUT_PORT_NUMB; j++)
|
||||
for (int arr_ind = 0; arr_ind < OUT_PORT_NUMB; arr_ind++)
|
||||
{
|
||||
Output = ssGetOutputPortRealSignal(S, j);
|
||||
for (int i = 0; i < outLengths[i]; i++)
|
||||
Output = ssGetOutputPortRealSignal(S, arr_ind);
|
||||
for (int val_ind = 0; val_ind < outLengths[arr_ind]; val_ind++)
|
||||
{
|
||||
global_index = XD_OUTPUT_START + outOffsets[j] + i;
|
||||
Output[i] = Out_Buff[global_index];
|
||||
global_index = XD_OUTPUT_START + outOffsets[arr_ind] + val_ind;
|
||||
Output[val_ind] = Out_Buff[global_index];
|
||||
Out_Buff[global_index] = 0;
|
||||
}
|
||||
}
|
||||
@@ -236,13 +236,13 @@ void SIM_readInputs(SimStruct* S)
|
||||
int global_index;
|
||||
|
||||
//-------------READING INPUTS---------------
|
||||
for (int j = 0; j < IN_PORT_NUMB; j++)
|
||||
for (int arr_ind = 0; arr_ind < IN_PORT_NUMB; arr_ind++)
|
||||
{
|
||||
Input = ssGetInputPortRealSignal(S, j);
|
||||
for (int i = 0; i < inLengths[j]; i++)
|
||||
Input = ssGetInputPortRealSignal(S, arr_ind);
|
||||
for (int val_ind = 0; val_ind < inLengths[arr_ind]; val_ind++)
|
||||
{
|
||||
global_index = XD_INPUT_START + inOffsets[j] + i;
|
||||
In_Buff[global_index] = Input[i];
|
||||
global_index = XD_INPUT_START + inOffsets[arr_ind] + val_ind;
|
||||
In_Buff[global_index] = Input[val_ind];
|
||||
}
|
||||
}
|
||||
//------------------------------------------
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
:: %4 — режим компиляции (debug/release)
|
||||
|
||||
:: Сохраняем как переменные
|
||||
set includes_USER=%~1
|
||||
set code_USER=%~2
|
||||
set defines_USER=%~3
|
||||
set defines_CONFIG=%~4
|
||||
set compil_mode=%~5
|
||||
set filename=%~1
|
||||
set includes_USER=%~2
|
||||
set code_USER=%~3
|
||||
set defines_USER=%~4
|
||||
set defines_CONFIG=%~5
|
||||
set compil_mode=%~6
|
||||
|
||||
:: Заменяем __EQ__ на =
|
||||
set defines_USER=%defines_USER:__EQ__==%
|
||||
@@ -51,15 +52,15 @@ set includes= %includes_WRAPPER% %includes_PERIPH% %includes_USER%
|
||||
set codes= %code_WRAPPER% %code_PERIPH% %code_USER%
|
||||
set defines= %defines_WRAPPER% %defines_CONFIG% %defines_USER%
|
||||
:: -------OUTPUT FOLDER--------
|
||||
set output= -outdir "."
|
||||
set output= -outdir "." -output %filename%
|
||||
|
||||
:: если нужен дебаг, до запускаем run_mex с припиской debug
|
||||
IF [%1]==[debug] (set debug= -g)
|
||||
IF %compil_mode%==debug (set debug= -g)
|
||||
::-------------------------------------------------------------------------
|
||||
|
||||
|
||||
::------START COMPILING-------
|
||||
if "%6"=="echo_enable" (
|
||||
if "%7"=="echo_enable" (
|
||||
echo Compiling...
|
||||
|
||||
echo ===========================
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file app_config.h
|
||||
* @brief Çàãîëîâî÷íûé ôàéë äëÿ ïîëüçîâàòåëüñêèõ êîíôèãóðàöèé.
|
||||
* @brief Заголовочный файл для пользовательских конфигураций.
|
||||
**************************************************************************/
|
||||
#ifndef _APP_CONFIG
|
||||
#define _APP_CONFIG
|
||||
|
||||
BIN
mcuwrapper.mltbx
BIN
mcuwrapper.mltbx
Binary file not shown.
@@ -1,19 +1,19 @@
|
||||
<deployment-project plugin="plugin.toolbox" plugin-version="1.0">
|
||||
<configuration file="E:\.WORK\MATLAB\matlab_23550\McuLib\mcuwrapper.prj" location="E:\.WORK\MATLAB\matlab_23550\McuLib" name="mcuwrapper" target="target.toolbox" target-name="Package Toolbox">
|
||||
<param.appname>mcuwrapper</param.appname>
|
||||
<configuration build-checksum="1721556499" file="E:\.WORK\MATLAB\mcu_matlab\mcuwrapper.prj" location="E:\.WORK\MATLAB\mcu_matlab" name="mcuwrapper" target="target.toolbox" target-name="Package Toolbox">
|
||||
<param.appname>MCU Wrapper</param.appname>
|
||||
<param.authnamewatermark>Razvalyaev</param.authnamewatermark>
|
||||
<param.email>wot890089@mail.ru</param.email>
|
||||
<param.company>NIO-12</param.company>
|
||||
<param.summary>Library for run MCU program in Simulink</param.summary>
|
||||
<param.description />
|
||||
<param.screenshot />
|
||||
<param.version>1.0</param.version>
|
||||
<param.output>${PROJECT_ROOT}\mcuwrapper.mltbx</param.output>
|
||||
<param.version>1.01</param.version>
|
||||
<param.output>${PROJECT_ROOT}\MCU Wrapper.mltbx</param.output>
|
||||
<param.products.name />
|
||||
<param.products.id />
|
||||
<param.products.version />
|
||||
<param.platforms />
|
||||
<param.guid>e7dd2564-e462-4878-b445-45763482263f</param.guid>
|
||||
<param.guid>bcf7498f-65f2-487f-b762-d3e88d9a4ebe</param.guid>
|
||||
<param.exclude.filters />
|
||||
<param.exclude.pcodedmfiles>true</param.exclude.pcodedmfiles>
|
||||
<param.examples />
|
||||
@@ -48,7 +48,6 @@
|
||||
<unset>
|
||||
<param.description />
|
||||
<param.screenshot />
|
||||
<param.version />
|
||||
<param.output />
|
||||
<param.products.name />
|
||||
<param.products.id />
|
||||
@@ -82,22 +81,22 @@
|
||||
<param.additional.sw.linux.url />
|
||||
</unset>
|
||||
<fileset.rootdir>
|
||||
<file>${PROJECT_ROOT}</file>
|
||||
<file>${PROJECT_ROOT}\McuLib</file>
|
||||
</fileset.rootdir>
|
||||
<fileset.rootfiles>
|
||||
<file>${PROJECT_ROOT}\install_my_library.m</file>
|
||||
<file>${PROJECT_ROOT}\lib</file>
|
||||
<file>${PROJECT_ROOT}\m</file>
|
||||
<file>${PROJECT_ROOT}\sl_customization.m</file>
|
||||
<file>${PROJECT_ROOT}\slblocks.m</file>
|
||||
<file>${PROJECT_ROOT}\startup.m</file>
|
||||
<file>${PROJECT_ROOT}\templates</file>
|
||||
<file>${PROJECT_ROOT}\McuLib\install_my_library.m</file>
|
||||
<file>${PROJECT_ROOT}\McuLib\lib</file>
|
||||
<file>${PROJECT_ROOT}\McuLib\m</file>
|
||||
<file>${PROJECT_ROOT}\McuLib\sl_customization.m</file>
|
||||
<file>${PROJECT_ROOT}\McuLib\slblocks.m</file>
|
||||
<file>${PROJECT_ROOT}\McuLib\startup.m</file>
|
||||
<file>${PROJECT_ROOT}\McuLib\templates</file>
|
||||
</fileset.rootfiles>
|
||||
<fileset.depfun.included />
|
||||
<fileset.depfun.excluded />
|
||||
<fileset.package />
|
||||
<build-deliverables>
|
||||
<file location="${PROJECT_ROOT}" name="mcuwrapper.mltbx" optional="false">E:\.WORK\MATLAB\matlab_23550\McuLib\mcuwrapper.mltbx</file>
|
||||
<file location="${PROJECT_ROOT}" name="MCU Wrapper.mltbx" optional="false">E:\.WORK\MATLAB\mcu_matlab\MCU Wrapper.mltbx</file>
|
||||
</build-deliverables>
|
||||
<workflow />
|
||||
<matlab>
|
||||
Reference in New Issue
Block a user