classdef asynchManage < handle % Менеджер асинхронных операций для работы с моделью Simulink % Решает проблемы блокировки модели при одновременном доступе из GUI % Использует таймеры для отложенного выполнения операций с моделью properties (Access = private) modelName % Имя модели Simulink для управления maskBlockPath % Полный путь к блоку с маской (если нужен доступ к GUI) timerSave % Таймер для операции сохранения модели timerUpdate % Таймер для операции обновления модели timerConfigUpdate % Таймер для обновления конфигурации end methods function obj = asynchManage(modelName, maskBlockPath) % Конструктор - создает менеджер для асинхронных операций % modelName - имя модели Simulink для управления % maskBlockPath - путь к блоку с маской (опционально, для GUI) obj.modelName = modelName; if nargin < 2 obj.maskBlockPath = ''; % Если не передали - работаем без GUI else obj.maskBlockPath = maskBlockPath; end end function saveAndUpdateModel(obj) % Асинхронное сохранение и обновление модели % Использует таймер чтобы избежать конфликтов доступа к модели obj.timerSave = timer(... 'StartDelay', 0.01, ... % Короткая задержка чтобы освободить модель 'ExecutionMode', 'singleShot', ... % Однократное выполнение 'TimerFcn', @(~,~) obj.saveCallback()); % Колбэк сохранения start(obj.timerSave); end function updateGUIfromConfig(obj) % Асинхронное обновление GUI из конфигурации % Используется когда нужно перезагрузить маску с новыми параметрами obj.timerConfigUpdate = timer(... 'StartDelay', 0.01, ... % Задержка для стабилизации модели 'ExecutionMode', 'singleShot', ... 'TimerFcn', @(~,~) obj.GUIconfigCallback()); % Колбэк обновления GUI start(obj.timerConfigUpdate); end end methods (Access = private) function saveCallback(obj) % Колбэк для сохранения модели - вызывается через таймер try % Закрываем маску чтобы разблокировать модель для сохранения mcuMask.close(obj.maskBlockPath); % Сохраняем модель (это могло бы вызвать конфликт без таймера) save_system(obj.modelName); catch ME warning('progr:Nneg', 'Ошибка при сохранении модели: %s', ME.message); end % Очищаем таймер сохранения stop(obj.timerSave); delete(obj.timerSave); obj.timerSave = []; % Запускаем таймер для обновления модели после сохранения obj.timerUpdate = timer(... 'StartDelay', 0.05, ... % Большая задержка для полного сохранения 'ExecutionMode', 'singleShot', ... 'TimerFcn', @(~,~) obj.updateCallback()); % Колбэк обновления start(obj.timerUpdate); end function updateCallback(obj) % Колбэк для обновления модели - вызывается после сохранения try % Команда обновления модели (перекомпиляция и т.д.) set_param(obj.modelName, 'SimulationCommand', 'update'); % Повторное сохранение после обновления save_system(obj.modelName); catch ME warning('progr:Nneg', 'Ошибка при обновлении модели: %s', ME.message); end % Переоткрываем маску если был указан путь к блоку if ~isempty(obj.maskBlockPath) try mcuMask.open(obj.maskBlockPath, 1); % Открываем маску снова catch ME warning('progr:Nneg', 'Не удалось открыть маску: %s', ME.message); end end % Очищаем таймер обновления stop(obj.timerUpdate); delete(obj.timerUpdate); obj.timerUpdate = []; end function GUIconfigCallback(obj) % Колбэк для обновления GUI из конфигурации try % Закрываем маску и выполняем настройку (mexing) mcuMask.close(obj.maskBlockPath); mexing(0); % Функция настройки/компиляции catch ME warning('progr:Nneg', 'Ошибка при обновлении модели: %s', ME.message); end % Переоткрываем маску с обновленными параметрами if ~isempty(obj.maskBlockPath) try mcuMask.open(obj.maskBlockPath, 1); % Открываем обновленную маску catch ME warning('progr:Nneg', 'Не удалось открыть маску: %s', ME.message); end end % Очищаем таймер обновления конфигурации stop(obj.timerConfigUpdate); delete(obj.timerConfigUpdate); obj.timerConfigUpdate = []; end end end