177 lines
8.8 KiB
Matlab
177 lines
8.8 KiB
Matlab
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 в этой периферии
|
||
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); % Создаем валидное имя параметра
|
||
|
||
% Проверяем существует ли параметр с таким именем в маске
|
||
if ismember(paramName, paramNames)
|
||
param = mask.getParameter(paramName);
|
||
valStr = param.Value; % Значение как строка из маски
|
||
|
||
% Проверяем существует ли элемент 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
|
||
end
|
||
end
|
||
end
|
||
end
|
||
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
|
||
config = [];
|
||
end
|
||
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);
|
||
|
||
% Записываем JSON в файл
|
||
fid = fopen(config_path, 'w', 'n', 'UTF-8');
|
||
if fid == -1
|
||
error('Не удалось открыть файл periph_config.json для записи.');
|
||
end
|
||
fwrite(fid, jsonText, 'char');
|
||
fclose(fid);
|
||
end
|
||
|
||
function value = get_field(configStruct, targetConfig)
|
||
% Рекурсивно ищет поле в структуре конфигурации
|
||
% configStruct - структура для поиска
|
||
% targetConfig - имя целевого поля
|
||
% Возвращает значение поля или пустой массив если не найдено
|
||
|
||
value = [];
|
||
fields = fieldnames(configStruct);
|
||
|
||
for i = 1:numel(fields)
|
||
key = fields{i};
|
||
if strcmp(key, targetConfig)
|
||
% Нашли прямое совпадение
|
||
value = configStruct.(key);
|
||
return;
|
||
elseif isstruct(configStruct.(key))
|
||
% Рекурсивно ищем во вложенной структуре
|
||
value = configJs.get_field(configStruct.(key), targetConfig);
|
||
if ~isempty(value)
|
||
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}; % Берём последний элемент
|
||
end
|
||
|
||
function value = convert_code_value(codeField)
|
||
% Преобразует значение поля Options в строку для отображения
|
||
% Обрабатывает разные типы данных: char, string, cell array
|
||
|
||
if ischar(codeField)
|
||
value = codeField;
|
||
elseif isstring(codeField)
|
||
value = char(codeField);
|
||
elseif iscell(codeField)
|
||
% Объединяем ячейки в одну строку с переносами
|
||
value = strjoin(codeField, newline);
|
||
else
|
||
% Для неподдерживаемых типов возвращаем пустую строку
|
||
value = '';
|
||
end
|
||
end
|
||
end
|
||
|
||
methods(Static, Access=private)
|
||
% Приватные методы могут быть добавлены здесь при необходимости
|
||
end
|
||
end |