mcu_matlab/McuLib/m/mainConfig.m
2025-11-07 14:52:52 +03:00

287 lines
13 KiB
Matlab
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

classdef mainConfig
% Класс для экспорта и импорта конфигурации маски Simulink в JSON
% Позволяет сохранять и загружать настройки блока между сессиями
methods(Static)
function config = export()
% Экспортирует текущую конфигурацию маски в JSON файл
% Сохраняет параметры обёртки, портов и приложения
blockPath = gcb;
mask = Simulink.Mask.get(blockPath);
% Списки параметров для экспорта по категориям
wrapParamToExport = {'wrapperPath', 'enableDebug', 'mcuClk', ...
'threadCycles', 'enableThreading', 'enableDeinit', ...
'periphPath'};
portParamToExport = {'inNumb', ...
'in_port_1_name', 'in_port_1_width', ...
'in_port_2_name', 'in_port_2_width', ...
'in_port_3_name', 'in_port_3_width', ...
'in_port_4_name', 'in_port_4_width', ...
'in_port_5_name', 'in_port_5_width', ...
'outNumb', ...
'out_port_1_name', 'out_port_1_width', ...
'out_port_2_name', 'out_port_2_width', ...
'out_port_3_name', 'out_port_3_width', ...
'out_port_4_name', 'out_port_4_width', ...
'out_port_5_name', 'out_port_5_width',};
appParamToExport = {'appWrapperPath', 'srcTable', 'incTable', 'userDefs'};
% Создаем структуру для конфигурации
config = struct();
% Экспортируем параметры обёртки
for i = 1:numel(wrapParamToExport)
paramName = wrapParamToExport{i};
def = mainConfig.exportParamToConfig(mask, paramName);
config.(paramName) = def;
end
% Экспортируем параметры портов
for i = 1:numel(portParamToExport)
paramName = portParamToExport{i};
def = mainConfig.exportParamToConfig(mask, paramName);
config.(paramName) = def;
end
% Экспортируем параметры приложения
for i = 1:numel(appParamToExport)
paramName = appParamToExport{i};
def = mainConfig.exportParamToConfig(mask, paramName);
config.(paramName) = def;
end
% Кодируем структуру в JSON с форматированием
jsonStr = jsonencode(config, 'PrettyPrint', true);
% Диалог сохранения файла
[file, path] = uiputfile('*.json', 'Сохранить конфигурацию как', 'WrapperConfig.json');
if isequal(file, 0) || isequal(path, 0)
disp('Сохранение отменено пользователем.');
return;
end
filepath = fullfile(path, file);
% Сохраняем в файл
fid = fopen(filepath, 'w');
if fid == -1
mcuMask.disp(0, 'Не удалось открыть файл для записи: %s', filename);
end
fwrite(fid, jsonStr, 'char');
fclose(fid);
end
function import()
% Импортирует конфигурацию маски из JSON файла
% Восстанавливает параметры обёртки, портов и приложения
% Получаем путь к текущему блоку
blockPath = gcb;
mask = Simulink.Mask.get(blockPath);
% Выбор JSON-файла через диалоговое окно
[file, path] = uigetfile('*.json', 'Выберите файл конфигурации');
if isequal(file, 0)
mcuMask.disp(0, 'Импорт отменён пользователем.');
return;
end
fullpath = fullfile(path, file);
% Чтение и декодирование JSON
try
jsonStr = fileread(fullpath);
config = jsondecode(jsonStr);
catch err
mcuMask.disp(0, 'Ошибка при чтении или разборе JSON: %s', err.message);
end
% Применение параметров из конфигурации
paramNames = fieldnames(config);
for i = 1:numel(paramNames)
paramName = paramNames{i};
def = config.(paramName);
try
mainConfig.applyDefToMask(mask, paramName, def);
catch err
mcuMask.disp(0, 'Ошибка при применении параметра "%s": %s', paramName, err.message);
end
end
mcuMask.disp(0, 'Конфигурация успешно импортирована.');
% Обновляем периферию после импорта
mcuMask.periphUpdate();
end
end
methods(Static, Access=private)
function def = exportParamToConfig(mask, paramName)
% Экспортирует один параметр маски в структуру для JSON
% mask - объект маски Simulink
% paramName - имя параметра для экспорта
% Возвращает структуру с описанием параметра
param = mask.getParameter(paramName);
if isempty(param)
mcuMask.disp(0, 'Параметр "%s" не найден в маске.', paramName);
def = [];
return;
end
def = struct();
% Сохраняем подпись параметра
def.Prompt = param.Prompt;
% Сохраняем тип параметра
def.Type = param.Type;
% Сохраняем значение в зависимости от типа
val = param.Value;
switch lower(param.Type)
case 'checkbox'
% Для чекбоксов преобразуем 'on'/'off' в true/false
def.Default = strcmp(val, 'on');
case {'edit', 'spinbox'}
% Для числовых полей пробуем преобразовать в число
num = str2double(val);
if ~isnan(num)
def.Default = num;
else
def.Default = val; % Оставляем строкой если не число
end
case 'customtable'
% Для таблиц парсим содержимое в cell-массив
def.Default = customtable.parse(param.Name);
case 'text'
% Для текстовых полей сохраняем пустую строку
def.Default = '';
otherwise
% Для остальных типов сохраняем как есть
def.Default = val;
end
% Сохраняем алиас если есть
if ~isempty(param.Alias)
def.Def = param.Alias;
end
end
function applyDefToMask(mask, paramName, def)
% Применяет параметр из конфигурации к маске
% mask - объект маски Simulink
% paramName - имя параметра для применения
% def - структура с данными параметра
% Получаем параметр из маски
param = mask.getParameter(paramName);
if isempty(param)
mcuMask.disp(0, 'Параметр "%s" не найден в маске.', paramName);
return;
end
if isempty(def)
mcuMask.disp(0, 'Параметр "%s" не найден в конфиге.', paramName);
return;
end
% Устанавливаем значение в зависимости от типа параметра
switch lower(def.Type)
case 'checkbox'
% Устанавливаем состояние чекбокса
if islogical(def.Default)
param.Value = mainConfig.ternary(def.Default, 'on', 'off');
else
mcuMask.disp(0, 'Ожидалось логическое значение для checkbox "%s".', paramName);
end
case {'edit', 'spinbox'}
% Устанавливаем значение для текстового поля
if isnumeric(def.Default)
param.Value = num2str(def.Default);
elseif ischar(def.Default) || isstring(def.Default)
param.Value = char(def.Default);
else
mcuMask.disp(0, 'Некорректный формат значения для edit "%s".', paramName);
end
case 'customtable'
% Загружаем данные в таблицу
if iscell(def.Default)
customtable.collect(paramName, def.Default);
else
mcuMask.disp(0, 'customtable "%s" требует cell-массив строк.', paramName);
end
case 'text'
% Устанавливаем текстовое значение
if ischar(def.Default) || isstring(def.Default)
param.Value = char(def.Default);
else
mcuMask.disp(0, 'text-параметр "%s" должен быть строкой.', paramName);
end
case 'popup'
% Устанавливаем значение выпадающего списка
if ischar(def.Default) && isfield(def, 'Def') && any(strcmp(def.Default, def.Def))
param.Value = def.Default;
else
mcuMask.disp(0, 'popup-параметр "%s" имеет неверное значение или список.', paramName);
end
otherwise
% Универсальная установка значения
if ischar(def.Default) || isstring(def.Default)
param.Value = char(def.Default);
elseif isnumeric(def.Default)
param.Value = num2str(def.Default);
else
mcuMask.disp(0, 'Неизвестный формат значения параметра "%s".', paramName);
end
end
% Обновляем подпись параметра если есть
if isfield(def, 'Prompt')
param.Prompt = def.Prompt;
end
% Обновляем алиас если есть
if isfield(def, 'Def') && ischar(def.Def)
param.Alias = def.Def;
end
% % Установка Row, если поддерживается
% if isfield(def, 'NewRow')
% try
% if def.NewRow
% param.DialogControl.Row = 'new';
% else
% param.DialogControl.Row = 'current';
% end
% catch
% % Некоторым типам параметров Row может быть неприменим
% end
% end
end
function result = ternary(cond, a, b)
% Вспомогательная функция - тернарный оператор
% cond - условие, a - значение если true, b - значение если false
if cond
result = a;
else
result = b;
end
end
end
end