Все изменения накопившиеся с релиза

This commit is contained in:
2025-11-14 21:56:39 +03:00
parent ac2fe4d653
commit 9b8b5ec533
17 changed files with 1008 additions and 699 deletions

View File

@@ -1,48 +1,61 @@
classdef configJs
% Класс для работы с JSON конфигурацией периферии в масках Simulink
% Обеспечивает чтение, запись и обновление конфигов из/в JSON файлы
methods(Static)
function config = update(blockPath, config)
% Обновляет конфигурацию значениями из маски Simulink
% blockPath - путь к блоку с маской
% config - структура конфигурации для обновления
if isempty(config)
return;
end
% Получаем маску и все её параметры
mask = Simulink.Mask.get(blockPath);
maskParams = mask.Parameters;
paramNames = arrayfun(@(p) p.Name, maskParams, 'UniformOutput', false);
% Обработка остальных секций (с дефайнами)
% Обрабатываем все секции периферии в конфиге
periphs = fieldnames(config);
for i = 1:numel(periphs)
periph = periphs{i};
% Проверяем есть ли Defines
% Проверяем есть ли секция Defines в этой периферии
if ~isfield(config.(periph), 'Defines')
continue;
end
% Получаем все определения (defines) для этой периферии
defines = config.(periph).Defines;
defNames = fieldnames(defines);
% Обходим все определения и обновляем их значения из маски
for j = 1:numel(defNames)
defPrompt = defNames{j};
paramName = matlab.lang.makeValidName(defPrompt);
paramName = matlab.lang.makeValidName(defPrompt); % Создаем валидное имя параметра
% Проверка, существует ли параметр с таким именем
% Проверяем существует ли параметр с таким именем в маске
if ismember(paramName, paramNames)
param = mask.getParameter(paramName);
valStr = param.Value;
valStr = param.Value; % Значение как строка из маски
% Проверяем, существует ли элемент defPrompt в структуре defines
% Проверяем существует ли элемент defPrompt в структуре defines
if isfield(defines, defPrompt)
% Преобразуем строку в соответствующий тип
% Преобразуем строку из маски в соответствующий тип данных
if strcmpi(defines.(defPrompt).Type, 'checkbox')
% Для чекбоксов преобразуем 'on'/'off' в true/false
config.(periph).Defines.(defPrompt).Default = strcmpi(valStr, 'on');
elseif strcmpi(defines.(defPrompt).Type, 'edit')
% Для текстовых полей пробуем преобразовать в число
valNum = str2double(valStr);
if isnan(valNum)
% Если не число - оставляем строкой
config.(periph).Defines.(defPrompt).Default = valStr;
else
% Если число - сохраняем как число
config.(periph).Defines.(defPrompt).Default = valNum;
end
end
@@ -53,12 +66,18 @@ classdef configJs
end
function config = read(blockPath)
% Читает JSON конфигурацию из файла указанного в маске
% blockPath - путь к блоку с маской
% Возвращает структуру конфигурации или пустой массив
mask = Simulink.Mask.get(blockPath);
% Получаем путь к конфигурационному файлу из параметра маски
pathparam = mask.getParameter('periphPath');
config_path = pathparam.Value;
if ~isempty(config_path)
% Читаем и декодируем JSON файл
jsonText = fileread(config_path);
config = jsondecode(jsonText);
else
@@ -67,18 +86,26 @@ classdef configJs
end
function write(config)
% Записывает конфигурацию обратно в JSON файл
% config - структура конфигурации для записи
if isempty(config)
return
end
% Получаем handle текущего блока и его маску
blockHandle = gcbh;
mask = Simulink.Mask.get(blockHandle);
% Получаем путь к конфигурационному файлу из маски
pathparam = mask.getParameter('periphPath');
config_path = pathparam.Value;
% Кодируем структуру в JSON с красивым форматированием
jsonText = jsonencode(config, 'PrettyPrint', true);
fid = fopen(config_path, 'w', 'n', 'UTF-8');
% Записываем JSON в файл
fid = fopen(config_path, 'w', 'n');
if fid == -1
error('Не удалось открыть файл periph_config.json для записи.');
end
@@ -86,58 +113,65 @@ classdef configJs
fclose(fid);
end
function value = get_field(configStruct, targetConfig)
% получить targetConfig структуру из конфига (для глубоко вложенных)
% Рекурсивно ищет поле в структуре конфигурации
% configStruct - структура для поиска
% targetConfig - имя целевого поля
% Возвращает значение поля или пустой массив если не найдено
value = [];
fields = fieldnames(configStruct);
for i = 1:numel(fields)
key = fields{i};
if strcmp(key, targetConfig)
% Нашли прямое совпадение
value = configStruct.(key);
return; % нашли и возвращаем
return;
elseif isstruct(configStruct.(key))
% Рекурсивно ищем во вложенной структуре
value = configJs.get_field(configStruct.(key), targetConfig);
if ~isempty(value)
return; % нашли во вложенной структуре
return; % Нашли во вложенной структуре
end
end
end
% Если не нашли, можно выбросить ошибку или вернуть пустое
% Если не нашли - возвращаем пустой массив
if isempty(value)
% Можно раскомментировать для отладки:
% error('Поле "%s" не найдено в структуре.', targetConfig);
end
end
function short = get_final_name_from_prefix(prefix)
% Берёт последнее имя после "_" (читаемое имя)
% Извлекает короткое имя из префикса (последняя часть после '_')
% prefix - строка с префиксом вида 'PREFIX_NAME'
% Возвращает последнюю часть после последнего '_'
parts = strsplit(prefix, '_');
short = parts{end};
short = parts{end}; % Берём последний элемент
end
function value = convert_code_value(codeField)
% Преобразует значение поля Options в строку
% Преобразует значение поля Options в строку для отображения
% Обрабатывает разные типы данных: char, string, cell array
if ischar(codeField)
value = codeField;
elseif isstring(codeField)
value = char(codeField);
elseif iscell(codeField)
% Объединяем ячейки в одну строку с переносами
value = strjoin(codeField, newline);
else
% warning('Неподдерживаемый тип данных: сохранено как пустая строка');
% Для неподдерживаемых типов возвращаем пустую строку
value = '';
end
end
end
methods(Static, Access=private)
% Приватные методы могут быть добавлены здесь при необходимости
end
end
end