Compare commits
	
		
			2 Commits
		
	
	
		
			ead46d7d82
			...
			5e93fc2099
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5e93fc2099 | |||
| 0a4a87038e | 
@ -9,11 +9,11 @@
 | 
			
		||||
//#define AHB_Prescaler	((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)
 | 
			
		||||
//#define AHB_Prescaler	((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)
 | 
			
		||||
 | 
			
		||||
#define HCLK_Value			(double)72000000;
 | 
			
		||||
#define ABP1_Value			(double)36000000;
 | 
			
		||||
#define ABP1_TIMS_Value		(double)72000000;
 | 
			
		||||
#define ABP2_Value			(double)72000000;
 | 
			
		||||
#define ABP2_TIMS_Value		(double)72000000;
 | 
			
		||||
//#define HCLK_Value			(double)72000000;
 | 
			
		||||
//#define ABP1_Value			(double)36000000;
 | 
			
		||||
//#define ABP1_TIMS_Value		(double)72000000;
 | 
			
		||||
//#define ABP2_Value			(double)72000000;
 | 
			
		||||
//#define ABP2_TIMS_Value		(double)72000000;
 | 
			
		||||
 | 
			
		||||
/* Эти дефайны добавлены в код stm32f4xx_hal_rcc.c, чтобы не попасть в бесконечный цикл */
 | 
			
		||||
/* Мб перенести в MCU_Periph_Simulation(), но чет не хочется нагружать симуляцию этой херней*/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										252
									
								
								MCU_STM32F1xx_Matlab/periph_config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								MCU_STM32F1xx_Matlab/periph_config.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,252 @@
 | 
			
		||||
{
 | 
			
		||||
  "RCC": {
 | 
			
		||||
    "Defines": {
 | 
			
		||||
      "HCLK_Clock": {
 | 
			
		||||
        "Prompt": "HCLK Clock (Hz)",
 | 
			
		||||
        "Def": "HCLK_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ABP1_Clock": {
 | 
			
		||||
        "Prompt": "ABP1 Clock (Hz)",
 | 
			
		||||
        "Def": "ABP1_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ABP1_TIMS_Clock": {
 | 
			
		||||
        "Prompt": "ABP1 Tim's Clock (Hz)",
 | 
			
		||||
        "Def": "ABP1_TIMS_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ABP2_Clock": {
 | 
			
		||||
        "Prompt": "ABP2 Clock (Hz)",
 | 
			
		||||
        "Def": "ABP2_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ABP2_TIMS_Clock": {
 | 
			
		||||
        "Prompt": "ABP2 Tim's Clock (Hz)",
 | 
			
		||||
        "Def": "ABP2_TIMS_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "TIM": {
 | 
			
		||||
    "Defines": {
 | 
			
		||||
      "TIM1_Enable": {
 | 
			
		||||
        "Prompt": "TIM1 Enable",
 | 
			
		||||
        "Def": "USE_TIM1",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM1_UP_TIM10_Handler": {
 | 
			
		||||
        "Prompt": "TIM1_UP_TIM10 Handler",
 | 
			
		||||
        "Def": "USE_TIM1_UP_TIM10_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM2_Enable": {
 | 
			
		||||
        "Prompt": "TIM2 Enable",
 | 
			
		||||
        "Def": "USE_TIM2",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM2_Handler": {
 | 
			
		||||
        "Prompt": "TIM2 Handler",
 | 
			
		||||
        "Def": "USE_TIM2_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM3_Enable": {
 | 
			
		||||
        "Prompt": "TIM3 Enable",
 | 
			
		||||
        "Def": "USE_TIM3",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM3_Handler": {
 | 
			
		||||
        "Prompt": "TIM3 Handler",
 | 
			
		||||
        "Def": "USE_TIM3_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM4_Enable": {
 | 
			
		||||
        "Prompt": "TIM4 Enable",
 | 
			
		||||
        "Def": "USE_TIM4",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM4_Handler": {
 | 
			
		||||
        "Prompt": "TIM4 Handler",
 | 
			
		||||
        "Def": "USE_TIM4_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM5_Enable": {
 | 
			
		||||
        "Prompt": "TIM5 Enable",
 | 
			
		||||
        "Def": "USE_TIM5",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM5_Handler": {
 | 
			
		||||
        "Prompt": "TIM5 Handler",
 | 
			
		||||
        "Def": "USE_TIM5_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM6_Enable": {
 | 
			
		||||
        "Prompt": "TIM6 Enable",
 | 
			
		||||
        "Def": "USE_TIM6",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM6_Handler": {
 | 
			
		||||
        "Prompt": "TIM6 Handler",
 | 
			
		||||
        "Def": "USE_TIM6_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM7_Enable": {
 | 
			
		||||
        "Prompt": "TIM7 Enable",
 | 
			
		||||
        "Def": "USE_TIM7",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM7_Handler": {
 | 
			
		||||
        "Prompt": "TIM7 Handler",
 | 
			
		||||
        "Def": "USE_TIM7_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM8_Enable": {
 | 
			
		||||
        "Prompt": "TIM8 Enable",
 | 
			
		||||
        "Def": "USE_TIM8",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM8_UP_TIM13_Handler": {
 | 
			
		||||
        "Prompt": "TIM8_UP_TIM13 Handler",
 | 
			
		||||
        "Def": "USE_TIM8_UP_TIM13_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM9_Enable": {
 | 
			
		||||
        "Prompt": "TIM9 Enable",
 | 
			
		||||
        "Def": "USE_TIM9",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM1_BRK_TIM9_Handler": {
 | 
			
		||||
        "Prompt": "TIM1_BRK_TIM9 Handler",
 | 
			
		||||
        "Def": "USE_TIM1_BRK_TIM9_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM10_Enable": {
 | 
			
		||||
        "Prompt": "TIM10 Enable",
 | 
			
		||||
        "Def": "USE_TIM10",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM11_Enable": {
 | 
			
		||||
        "Prompt": "TIM11 Enable",
 | 
			
		||||
        "Def": "USE_TIM11",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM1_TRG_COM_TIM11_Handler": {
 | 
			
		||||
        "Prompt": "TIM1_TRG_COM_TIM11 Handler",
 | 
			
		||||
        "Def": "USE_TIM1_TRG_COM_TIM11_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM12_Enable": {
 | 
			
		||||
        "Prompt": "TIM12 Enable",
 | 
			
		||||
        "Def": "USE_TIM12",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM8_BRK_TIM12_Handler": {
 | 
			
		||||
        "Prompt": "TIM8_BRK_TIM12 Handler",
 | 
			
		||||
        "Def": "USE_TIM8_BRK_TIM12_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM13_Enable": {
 | 
			
		||||
        "Prompt": "TIM13 Enable",
 | 
			
		||||
        "Def": "USE_TIM13",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM14_Enable": {
 | 
			
		||||
        "Prompt": "TIM14 Enable",
 | 
			
		||||
        "Def": "USE_TIM14",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM8_TRG_COM_TIM14_Handler": {
 | 
			
		||||
        "Prompt": "TIM8_TRG_COM_TIM14 Handler",
 | 
			
		||||
        "Def": "USE_TIM8_TRG_COM_TIM14_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "ADC": {
 | 
			
		||||
    "Defines": {
 | 
			
		||||
      "ADC1_Enable": {
 | 
			
		||||
        "Prompt": "ADC1 Enable",
 | 
			
		||||
        "Def": "ADC1_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ADC2_Enable": {
 | 
			
		||||
        "Prompt": "ADC2 Enable",
 | 
			
		||||
        "Def": "ADC2_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "Sample_Rate": {
 | 
			
		||||
        "Prompt": "Sample Rate (Hz)",
 | 
			
		||||
        "Def": "SAMPLE_RATE",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 48000,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -12,7 +12,7 @@
 | 
			
		||||
// DEFINES (UNCOMMENT WHAT YOU WILL SIMULATE)
 | 
			
		||||
// TIMS
 | 
			
		||||
//#define USE_TIM1
 | 
			
		||||
#define USE_TIM2
 | 
			
		||||
//#define USE_TIM2
 | 
			
		||||
//#define USE_TIM3
 | 
			
		||||
//#define USE_TIM4
 | 
			
		||||
//#define USE_TIM5
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										718
									
								
								MCU_Wrapper/mexing.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										718
									
								
								MCU_Wrapper/mexing.m
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,718 @@
 | 
			
		||||
% Компилирует S-function
 | 
			
		||||
function mexing(compile_mode)
 | 
			
		||||
    global Ts
 | 
			
		||||
    Ts = 0.00001;
 | 
			
		||||
    
 | 
			
		||||
    if compile_mode == 1
 | 
			
		||||
        delete("*.mexw64")
 | 
			
		||||
        delete("*.mexw64.pdb")
 | 
			
		||||
        delete(".\MCU_Wrapper\Outputs\*.*");
 | 
			
		||||
        set_param(gcb, 'consoleOutput', '');    
 | 
			
		||||
        % Дефайны
 | 
			
		||||
        definesWrapperArg = buildWrapperDefinesString();
 | 
			
		||||
        definesUserArg = parseDefinesMaskText();
 | 
			
		||||
        definesConfigArg = buildConfigDefinesString();
 | 
			
		||||
        definesAllArg = [definesUserArg + " " + definesWrapperArg  + " " + definesConfigArg];    
 | 
			
		||||
            
 | 
			
		||||
        %режимы компиляции
 | 
			
		||||
        if read_checkbox('enableDebug')
 | 
			
		||||
            modeArg = "debug";
 | 
			
		||||
        else
 | 
			
		||||
            modeArg = "release";
 | 
			
		||||
        end    
 | 
			
		||||
        if read_checkbox('fullOutput') || read_checkbox('extConsol') 
 | 
			
		||||
            echoArg = 'echo_enable';
 | 
			
		||||
        else
 | 
			
		||||
            echoArg = 'echo_disable';    
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        [includesArg, codeArg] = make_mex_arguments('incTable', 'srcTable');
 | 
			
		||||
        
 | 
			
		||||
        % Вызов батника с двумя параметрами: includes и code
 | 
			
		||||
        cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" %s %s', includesArg, codeArg, definesAllArg, modeArg, echoArg);
 | 
			
		||||
            
 | 
			
		||||
        if read_checkbox('extConsol')
 | 
			
		||||
            cmdout = runBatAndShowOutput(cmd);
 | 
			
		||||
        else
 | 
			
		||||
            [status, cmdout]= system(cmd);
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        % Сохраним вывод в параметр маски с именем 'consoleOutput'
 | 
			
		||||
        set_param(gcb, 'consoleOutput', cmdout);
 | 
			
		||||
        
 | 
			
		||||
        beep
 | 
			
		||||
    else
 | 
			
		||||
        blockPath = bdroot;
 | 
			
		||||
        config = read_periph_config();
 | 
			
		||||
        config = update_config_from_mask(blockPath, config);
 | 
			
		||||
        write_periph_config(config);
 | 
			
		||||
        update_mask_from_config(blockPath, config);
 | 
			
		||||
        % set_param(gcb, 'consoleOutput', 'Peripheral configuration file loaded. Re-open Block Parameters');
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
%% COMPILE PARAMS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function [includesArg, codeArg] = make_mex_arguments(incTableName, srcTableame)
 | 
			
		||||
%MAKE_MEX_ARGUMENTS Формирует строки аргументов для вызова mex-компиляции через батник
 | 
			
		||||
%
 | 
			
		||||
% [includesArg, codeArg] = make_mex_arguments(includesCell, codeCell)
 | 
			
		||||
%
 | 
			
		||||
% Вход:
 | 
			
		||||
%   includesCell — ячейковый массив путей к директориям include
 | 
			
		||||
%   codeCell     — ячейковый массив исходных файлов
 | 
			
		||||
%
 | 
			
		||||
% Выход:
 | 
			
		||||
%   includesArg  — строка для передачи в батник, например: "-I"inc1" -I"inc2""
 | 
			
		||||
%   codeArg      — строка с исходниками, например: ""src1.c" "src2.cpp""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    % Здесь пример получения из маски текущего блока (замени по своему)
 | 
			
		||||
    blockHandle = gcbh;  % или замени на нужный блок
 | 
			
		||||
 | 
			
		||||
    includesCell = parseCellString(get_param(blockHandle, incTableName));
 | 
			
		||||
    codeCell = parseCellString(get_param(blockHandle, srcTableame));
 | 
			
		||||
 | 
			
		||||
    % Оборачиваем пути в кавычки и добавляем -I
 | 
			
		||||
    includesStr = strjoin(cellfun(@(f) ['-I"' f '"'], includesCell, 'UniformOutput', false), ' ');
 | 
			
		||||
 | 
			
		||||
    % Оборачиваем имена файлов в кавычки
 | 
			
		||||
    codeStr = strjoin(cellfun(@(f) ['"' f '"'], codeCell, 'UniformOutput', false), ' ');
 | 
			
		||||
 | 
			
		||||
    % Удаляем символ переноса строки и пробел в конце, если вдруг попал
 | 
			
		||||
    codeStr = strtrim(codeStr);
 | 
			
		||||
    includesStr = strtrim(includesStr);
 | 
			
		||||
 | 
			
		||||
    % Оборачиваем всю строку в кавычки, чтобы батник корректно понял
 | 
			
		||||
    % includesArg = ['"' includesStr '"'];
 | 
			
		||||
    % codeArg = ['"' codeStr '"'];
 | 
			
		||||
    includesArg = includesStr;
 | 
			
		||||
    codeArg = codeStr;
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function definesWrapperArg = buildWrapperDefinesString()
 | 
			
		||||
 | 
			
		||||
    definesWrapperArg = '';
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'enableThreading', 0);
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'enableDeinit', 0);
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'threadCycles', 1);
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'mcuClk', 1);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function definesUserArg = parseDefinesMaskText()
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
    % Получаем MaskValues и MaskNames
 | 
			
		||||
    maskValues = get_param(blockHandle, 'MaskValues');
 | 
			
		||||
    paramNames = get_param(blockHandle, 'MaskNames');
 | 
			
		||||
 | 
			
		||||
    % Индекс параметра userDefs
 | 
			
		||||
    idxUserDefs = find(strcmp(paramNames, 'userDefs'));
 | 
			
		||||
    definesText = maskValues{idxUserDefs}; % Текст с пользовательскими определениями
 | 
			
		||||
 | 
			
		||||
    % Убираем буквальные символы \n и \r
 | 
			
		||||
    definesText = strrep(definesText, '\n', ' ');
 | 
			
		||||
    definesText = strrep(definesText, '\r', ' ');
 | 
			
		||||
 | 
			
		||||
    % Разбиваем по переносам строк
 | 
			
		||||
    lines = split(definesText, {'\n', '\r\n', '\r'});
 | 
			
		||||
 | 
			
		||||
    parts = strings(1,0); % пустой массив строк
 | 
			
		||||
 | 
			
		||||
    for k = 1:numel(lines)
 | 
			
		||||
        line = strtrim(lines{k});
 | 
			
		||||
        if isempty(line)
 | 
			
		||||
            continue;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Разбиваем по пробелам, чтобы получить отдельные определения в строке
 | 
			
		||||
        tokens = split(line);
 | 
			
		||||
 | 
			
		||||
        for t = 1:numel(tokens)
 | 
			
		||||
            token = strtrim(tokens{t});
 | 
			
		||||
            if isempty(token)
 | 
			
		||||
                continue;
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            eqIdx = strfind(token, '=');
 | 
			
		||||
            if isempty(eqIdx)
 | 
			
		||||
                % Просто ключ без значения
 | 
			
		||||
                parts(end+1) = sprintf('-D"%s"', token);
 | 
			
		||||
            else
 | 
			
		||||
                key = strtrim(token(1:eqIdx(1)-1));
 | 
			
		||||
                val = strtrim(token(eqIdx(1)+1:end));
 | 
			
		||||
                parts(end+1) = sprintf('-D"%s__EQ__%s"', key, val);
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    definesUserArg = strjoin(parts, ' ');
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function definesWrapperArg = buildConfigDefinesString()
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
    mask = Simulink.Mask.get(blockHandle);
 | 
			
		||||
 | 
			
		||||
    tabName = 'configTab';  % Имя вкладки (Prompt)
 | 
			
		||||
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    tabCtrl = find_tab_by_name(allControls, tabName);
 | 
			
		||||
 | 
			
		||||
    if isempty(tabCtrl)
 | 
			
		||||
        error('Вкладка с названием "%s" не найдена в маске', tabName);
 | 
			
		||||
    end
 | 
			
		||||
    definesWrapperArg = '';
 | 
			
		||||
    % Получаем все контролы внутри вкладки
 | 
			
		||||
    children = tabCtrl.DialogControls;
 | 
			
		||||
    for i = 1:numel(children)
 | 
			
		||||
        ctrl = children(i);
 | 
			
		||||
        % Получаем имя параметра из контрола
 | 
			
		||||
        paramName = ctrl.Name;
 | 
			
		||||
            try
 | 
			
		||||
                % Получаем объект параметра по имени
 | 
			
		||||
                param = mask.getParameter(paramName);
 | 
			
		||||
    
 | 
			
		||||
                % Определяем тип параметра
 | 
			
		||||
                switch lower(param.Type)
 | 
			
		||||
                    case 'checkbox'
 | 
			
		||||
                        definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0);
 | 
			
		||||
                    case 'edit'
 | 
			
		||||
                        definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1);
 | 
			
		||||
                    otherwise
 | 
			
		||||
                        % Необрабатываемые типы
 | 
			
		||||
                end
 | 
			
		||||
            catch ME
 | 
			
		||||
                warning('Не удалось получить параметр "%s": %s', paramName, ME.message);
 | 
			
		||||
            end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% PARSE FUNCTIONS
 | 
			
		||||
 | 
			
		||||
function out = parseCellString(str)
 | 
			
		||||
    str = strtrim(str);
 | 
			
		||||
    if startsWith(str, '{') && endsWith(str, '}')
 | 
			
		||||
        str = str(2:end-1);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    parts = split(str, ';');
 | 
			
		||||
    out = cell(numel(parts), 1);
 | 
			
		||||
    for i = 1:numel(parts)
 | 
			
		||||
        el = strtrim(parts{i});
 | 
			
		||||
        if startsWith(el, '''') && endsWith(el, '''')
 | 
			
		||||
            el = el(2:end-1);
 | 
			
		||||
        end
 | 
			
		||||
        out{i} = el;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if isempty(out) || (numel(out) == 1 && isempty(out{1}))
 | 
			
		||||
        out = {};
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function str = cellArrayToString(cellArray)
 | 
			
		||||
    quoted = cellfun(@(s) ['''' s ''''], cellArray, 'UniformOutput', false);
 | 
			
		||||
    str = ['{' strjoin(quoted, ';') '}'];
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, val_define)
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
    mask = Simulink.Mask.get(blockHandle);
 | 
			
		||||
 | 
			
		||||
    % Получаем MaskValues, MaskNames
 | 
			
		||||
    maskValues = get_param(blockHandle, 'MaskValues');
 | 
			
		||||
    paramNames = get_param(blockHandle, 'MaskNames');
 | 
			
		||||
    param = mask.getParameter(paramName); % для alias
 | 
			
		||||
 | 
			
		||||
    % Найдём индекс нужного параметра
 | 
			
		||||
    idxParam = find(strcmp(paramNames, paramName), 1);
 | 
			
		||||
    if isempty(idxParam)
 | 
			
		||||
        error('Parameter "%s" not found in block mask parameters.', paramName);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Берём alias из маски
 | 
			
		||||
    alias = param.Alias;
 | 
			
		||||
 | 
			
		||||
    if val_define ~= 0
 | 
			
		||||
        % Значение параметра
 | 
			
		||||
        val = maskValues{idxParam};
 | 
			
		||||
        % Формируем define с кавычками и значением
 | 
			
		||||
        newDefine = ['-D"' alias '__EQ__' val '"'];
 | 
			
		||||
    else
 | 
			
		||||
        if read_checkbox(paramName)
 | 
			
		||||
            % Формируем define с кавычками без значения
 | 
			
		||||
            newDefine = ['-D"' alias '"'];
 | 
			
		||||
        else
 | 
			
		||||
            newDefine = '';
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    % Добавляем новый define к существующему (string)
 | 
			
		||||
    if isempty(definesWrapperArg) || strlength(strtrim(definesWrapperArg)) == 0
 | 
			
		||||
        definesWrapperArg = newDefine;
 | 
			
		||||
    else
 | 
			
		||||
        definesWrapperArg = definesWrapperArg + " " + newDefine;
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function checkbox_state = read_checkbox(checkboxName)
 | 
			
		||||
    maskValues = get_param(gcbh, 'MaskValues');
 | 
			
		||||
    paramNames = get_param(gcbh, 'MaskNames');
 | 
			
		||||
    
 | 
			
		||||
    inxCheckBox = find(strcmp(paramNames, checkboxName));
 | 
			
		||||
    
 | 
			
		||||
    checkbox_state_str = maskValues{inxCheckBox};
 | 
			
		||||
    if strcmpi(checkbox_state_str, 'on')
 | 
			
		||||
        checkbox_state = 1;
 | 
			
		||||
    else
 | 
			
		||||
        checkbox_state = 0;
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
%% CONSOLE FUNCTIONS
 | 
			
		||||
 | 
			
		||||
function cmdret = runBatAndShowOutput(cmd)
 | 
			
		||||
    import java.io.*;
 | 
			
		||||
    import java.lang.*;
 | 
			
		||||
    cmdEnglish = ['chcp 437 > nul && ' cmd];
 | 
			
		||||
    pb = java.lang.ProcessBuilder({'cmd.exe', '/c', cmdEnglish});
 | 
			
		||||
    pb.redirectErrorStream(true);
 | 
			
		||||
    process = pb.start();
 | 
			
		||||
 | 
			
		||||
    reader = BufferedReader(InputStreamReader(process.getInputStream()));
 | 
			
		||||
 | 
			
		||||
    cmdret = ""; % Здесь будем накапливать весь вывод
 | 
			
		||||
 | 
			
		||||
    while true
 | 
			
		||||
        if reader.ready()
 | 
			
		||||
            line = char(reader.readLine());
 | 
			
		||||
            if isempty(line)
 | 
			
		||||
                break;
 | 
			
		||||
            end
 | 
			
		||||
            cmdret = cmdret + string(line) + newline; % сохраняем вывод
 | 
			
		||||
            % Здесь выводим только новую строку
 | 
			
		||||
            safeLine = strrep(line, '''', ''''''); % Экранируем апострофы
 | 
			
		||||
            logWindow_append(safeLine);
 | 
			
		||||
            drawnow; % обновляем GUI
 | 
			
		||||
        else
 | 
			
		||||
            if ~process.isAlive()
 | 
			
		||||
                % дочитываем оставшиеся строки
 | 
			
		||||
                while reader.ready()
 | 
			
		||||
                    line = char(reader.readLine());
 | 
			
		||||
                    if isempty(line)
 | 
			
		||||
                        break;
 | 
			
		||||
                    end
 | 
			
		||||
                    cmdret = cmdret + string(line) + newline; % сохраняем вывод
 | 
			
		||||
                    safeLine = strrep(line, '''', '''''');
 | 
			
		||||
                    logWindow_append(safeLine);
 | 
			
		||||
                    drawnow;
 | 
			
		||||
                end
 | 
			
		||||
                break;
 | 
			
		||||
            end
 | 
			
		||||
            pause(0.2);
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    process.waitFor();
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function logWindow_append(line)
 | 
			
		||||
    persistent fig hEdit jScrollPane jTextArea
 | 
			
		||||
 | 
			
		||||
    if isempty(fig) || ~isvalid(fig)
 | 
			
		||||
        fig = figure('Name', 'Log Window', 'Position', [100 100 600 400]);
 | 
			
		||||
        hEdit = uicontrol('Style', 'edit', ...
 | 
			
		||||
            'Max', 2, 'Min', 0, ...
 | 
			
		||||
            'Enable', 'on', ...
 | 
			
		||||
            'FontName', 'Courier New', ...
 | 
			
		||||
            'Position', [10 10 580 380], ...
 | 
			
		||||
            'HorizontalAlignment', 'left', ...
 | 
			
		||||
            'BackgroundColor', 'white', ...
 | 
			
		||||
            'Tag', 'LogWindowFigure');
 | 
			
		||||
 | 
			
		||||
        jScrollPane = findjobj(hEdit);                  % JScrollPane
 | 
			
		||||
        jTextArea = jScrollPane.getViewport.getView;   % JTextArea внутри JScrollPane
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    oldText = get(hEdit, 'String');
 | 
			
		||||
    if ischar(oldText)
 | 
			
		||||
        oldText = {oldText};
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    set(hEdit, 'String', [oldText; {line}]);
 | 
			
		||||
    drawnow;
 | 
			
		||||
    % Автоскролл вниз:
 | 
			
		||||
    jTextArea.setCaretPosition(jTextArea.getDocument.getLength);
 | 
			
		||||
    drawnow;
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% READ CONFIGS
 | 
			
		||||
function config = read_periph_config()
 | 
			
		||||
    jsonText = fileread('periph_config.json');
 | 
			
		||||
    config = jsondecode(jsonText);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function write_periph_config(config)
 | 
			
		||||
    jsonText = jsonencode(config, 'PrettyPrint', true);
 | 
			
		||||
    fid = fopen('periph_config.json', 'w');
 | 
			
		||||
    if fid == -1
 | 
			
		||||
        error('Не удалось открыть файл periph_config.json для записи.');
 | 
			
		||||
    end
 | 
			
		||||
    fwrite(fid, jsonText, 'char');
 | 
			
		||||
    fclose(fid);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
%% CONFIG MASK TOOLS
 | 
			
		||||
function update_mask_from_config(blockPath, config)
 | 
			
		||||
    blockPath = [blockPath '/MCU'];
 | 
			
		||||
 | 
			
		||||
    % Проверяем, была ли маска открыта
 | 
			
		||||
    wasOpen = isMaskDialogOpen(blockPath);
 | 
			
		||||
    close_system(blockPath, 0);
 | 
			
		||||
    mask = Simulink.Mask.get(blockPath);
 | 
			
		||||
    
 | 
			
		||||
    tableNames = {'incTable', 'srcTable'};
 | 
			
		||||
    columns_backup = clear_tables(blockPath, tableNames);
 | 
			
		||||
 | 
			
		||||
    containerName = 'configTabAll';
 | 
			
		||||
    clear_all_from_container(mask, containerName);
 | 
			
		||||
 | 
			
		||||
    % Ищем контейнер, в который будем добавлять вкладки
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    container = find_container_by_name(allControls, containerName);
 | 
			
		||||
    if isempty(container)
 | 
			
		||||
        error('Контейнер "%s" не найден в маске.', containerName);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Проходим по каждому модулю (ADC, TIM...)
 | 
			
		||||
    periphs = fieldnames(config);
 | 
			
		||||
    for i = 1:numel(periphs)
 | 
			
		||||
        periph = periphs{i};
 | 
			
		||||
        defines = config.(periph).Defines;
 | 
			
		||||
        defNames = fieldnames(defines);
 | 
			
		||||
 | 
			
		||||
        % Создаём вкладку для модуля
 | 
			
		||||
        tabCtrl = container.addDialogControl('tab', periph);
 | 
			
		||||
        tabCtrl.Prompt = [periph ' Config'];
 | 
			
		||||
 | 
			
		||||
        for j = 1:numel(defNames)
 | 
			
		||||
            defPrompt = defNames{j};
 | 
			
		||||
            def = defines.(defPrompt);
 | 
			
		||||
            prompt = def.Prompt;
 | 
			
		||||
 | 
			
		||||
            % Только checkbox и edit
 | 
			
		||||
            switch lower(def.Type)
 | 
			
		||||
                case 'checkbox'
 | 
			
		||||
                    paramType = 'checkbox';
 | 
			
		||||
                case 'edit'
 | 
			
		||||
                    paramType = 'edit';
 | 
			
		||||
                otherwise
 | 
			
		||||
                    continue;
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            paramName = matlab.lang.makeValidName(defPrompt);
 | 
			
		||||
 | 
			
		||||
            % Преобразуем значение по типу
 | 
			
		||||
            val = def.Default;
 | 
			
		||||
            if islogical(val)
 | 
			
		||||
                if val
 | 
			
		||||
                    valStr = 'on';
 | 
			
		||||
                else
 | 
			
		||||
                    valStr = 'off';
 | 
			
		||||
                end
 | 
			
		||||
            elseif isnumeric(val)
 | 
			
		||||
                valStr = num2str(val);
 | 
			
		||||
            elseif ischar(val)
 | 
			
		||||
                valStr = val;
 | 
			
		||||
            else
 | 
			
		||||
                error('Unsupported default value type for %s.%s', periph, defPrompt);
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            % Добавляем параметр в соответствующую вкладку
 | 
			
		||||
            param = mask.addParameter( ...
 | 
			
		||||
                'Type', paramType, ...
 | 
			
		||||
                'Prompt', prompt, ...
 | 
			
		||||
                'Name', paramName, ...
 | 
			
		||||
                'Value', valStr, ...
 | 
			
		||||
                'Container', periph ...
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            param.Alias = def.Def;
 | 
			
		||||
            if def.NewRow
 | 
			
		||||
                row_param = 'new';
 | 
			
		||||
            else
 | 
			
		||||
                row_param = 'current';
 | 
			
		||||
            end
 | 
			
		||||
            param.DialogControl.Row = row_param;
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Восстанавливаем таблицы
 | 
			
		||||
    restore_tables(blockPath, tableNames, columns_backup);
 | 
			
		||||
 | 
			
		||||
    % Повторно открываем маску, если она была открыта
 | 
			
		||||
    if wasOpen
 | 
			
		||||
        open_system(blockPath, 'mask');
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function config = update_config_from_mask(blockPath, config)
 | 
			
		||||
    blockPath = [blockPath '/MCU'];
 | 
			
		||||
    mask = Simulink.Mask.get(blockPath);
 | 
			
		||||
 | 
			
		||||
    periphs = fieldnames(config);
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(periphs)
 | 
			
		||||
        periph = periphs{i};
 | 
			
		||||
        defines = config.(periph).Defines;
 | 
			
		||||
        defNames = fieldnames(defines);
 | 
			
		||||
 | 
			
		||||
        for j = 1:numel(defNames)
 | 
			
		||||
            defPrompt = defNames{j};
 | 
			
		||||
            paramName = matlab.lang.makeValidName(defPrompt);
 | 
			
		||||
            param = mask.getParameter(paramName);
 | 
			
		||||
 | 
			
		||||
            % Получаем значение из маски и сохраняем в конфиг
 | 
			
		||||
            valStr = param.Value;
 | 
			
		||||
 | 
			
		||||
            % Преобразуем строку в соответствующий тип
 | 
			
		||||
            if strcmpi(defines.(defPrompt).Type, 'checkbox')
 | 
			
		||||
                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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function clear_all_from_container(mask, containerName)
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    container = find_container_by_name(allControls, containerName);
 | 
			
		||||
    if isempty(container)
 | 
			
		||||
        warning('Контейнер "%s" не найден.', containerName);
 | 
			
		||||
        return;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Рекурсивно собрать все параметры (не вкладки)
 | 
			
		||||
    paramsToDelete = collect_all_parameters(container);
 | 
			
		||||
 | 
			
		||||
    % Удаляем все параметры
 | 
			
		||||
    for i = 1:numel(paramsToDelete)
 | 
			
		||||
        try
 | 
			
		||||
            mask.removeParameter(paramsToDelete{i});
 | 
			
		||||
        catch
 | 
			
		||||
            warning('Не удалось удалить параметр %s', paramsToDelete{i});
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Рекурсивно удалить все вкладки внутри контейнера
 | 
			
		||||
    delete_all_tabs(mask, container);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function params = collect_all_parameters(container)
 | 
			
		||||
    params = {};
 | 
			
		||||
    children = container.DialogControls;
 | 
			
		||||
    for i = 1:numel(children)
 | 
			
		||||
        ctrl = children(i);
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab')
 | 
			
		||||
            % Если вкладка — рекурсивно собираем параметры внутри неё
 | 
			
		||||
            params = [params, collect_all_parameters(ctrl)];
 | 
			
		||||
        else
 | 
			
		||||
            % Иначе это параметр — добавляем имя
 | 
			
		||||
            params{end+1} = ctrl.Name; %#ok<AGROW>
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function delete_all_tabs(mask, container)
 | 
			
		||||
    children = container.DialogControls;
 | 
			
		||||
    % Идём в обратном порядке, чтобы безопасно удалять
 | 
			
		||||
    for i = numel(children):-1:1
 | 
			
		||||
        ctrl = children(i);
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab')
 | 
			
		||||
            % Сначала рекурсивно удаляем вкладки внутри текущей вкладки
 | 
			
		||||
            delete_all_tabs(mask, ctrl);
 | 
			
		||||
            try
 | 
			
		||||
                container.removeDialogControl(ctrl.Name);
 | 
			
		||||
            catch ME
 | 
			
		||||
                warning('Не удалось удалить вкладку %s: %s', ctrl.Name, ME.message);
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function isOpen = isMaskDialogOpen(blockPath)
 | 
			
		||||
    isOpen = false;
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
        % Получаем имя блока
 | 
			
		||||
        blockName = get_param(blockPath, 'Name');
 | 
			
		||||
 | 
			
		||||
        % Получаем список окон MATLAB GUI
 | 
			
		||||
        jWindows = java.awt.Window.getWindows();
 | 
			
		||||
 | 
			
		||||
        for i = 1:numel(jWindows)
 | 
			
		||||
            win = jWindows(i);
 | 
			
		||||
 | 
			
		||||
            % Проверка, что окно видимое и активно
 | 
			
		||||
            if win.isShowing()
 | 
			
		||||
                try
 | 
			
		||||
                    title = char(win.getTitle());
 | 
			
		||||
                    % Проверка по ключевому слову, соответствующему заголовку маски
 | 
			
		||||
                    if contains(title, ['Mask Editor: ' blockName]) || ...
 | 
			
		||||
                       contains(title, ['Mask: ' blockName]) || ...
 | 
			
		||||
                       contains(title, blockName)
 | 
			
		||||
                        isOpen = true;
 | 
			
		||||
                        return;
 | 
			
		||||
                    end
 | 
			
		||||
                catch
 | 
			
		||||
                    % Окно не имеет заголовка — пропускаем
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    catch
 | 
			
		||||
        isOpen = false;
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function column_titles = clear_tables(block, table_names)
 | 
			
		||||
    % Очищает столбцы в каждой таблице из массива имен table_names
 | 
			
		||||
    % Возвращает cell-массив с названиями первых столбцов каждой таблицы
 | 
			
		||||
    
 | 
			
		||||
    % Получить объект маски блока
 | 
			
		||||
    maskObj = Simulink.Mask.get(block);
 | 
			
		||||
    
 | 
			
		||||
    % Инициализировать cell-массив для хранения названий столбцов
 | 
			
		||||
    column_titles = cell(size(table_names));
 | 
			
		||||
    
 | 
			
		||||
    for k = 1:numel(table_names)
 | 
			
		||||
        table_name = table_names{k};
 | 
			
		||||
        
 | 
			
		||||
        % Получить объект управления таблицей
 | 
			
		||||
        tableControl = maskObj.getDialogControl(table_name);
 | 
			
		||||
        
 | 
			
		||||
        % Получить количество столбцов
 | 
			
		||||
        nCols = tableControl.getNumberOfColumns;
 | 
			
		||||
        
 | 
			
		||||
        if nCols > 0
 | 
			
		||||
            % Получить первый столбец (который будем удалять)
 | 
			
		||||
            column = tableControl.getColumn(1);
 | 
			
		||||
            column_titles{k} = column.Name;
 | 
			
		||||
            
 | 
			
		||||
            % Удаляем все столбцы
 | 
			
		||||
            % Важно: при удалении столбцов индексы меняются, 
 | 
			
		||||
            % поэтому удаляем всегда первый столбец nCols раз
 | 
			
		||||
            for i = 1:nCols
 | 
			
		||||
                tableControl.removeColumn(1);
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            % Если столбцов нет, возвращаем пустую строку
 | 
			
		||||
            column_titles{k} = '';
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function restore_tables(block, table_names, column_titles)
 | 
			
		||||
    % Восстанавливает первый столбец в каждой таблице из массива имен
 | 
			
		||||
    % Использует массив column_titles для установки имени столбца
 | 
			
		||||
    
 | 
			
		||||
    % Получить объект маски блока
 | 
			
		||||
    maskObj = Simulink.Mask.get(block);
 | 
			
		||||
    
 | 
			
		||||
    for k = 1:numel(table_names)
 | 
			
		||||
        table_name = table_names{k};
 | 
			
		||||
        title = column_titles{k};
 | 
			
		||||
        
 | 
			
		||||
        % Получить объект управления таблицей
 | 
			
		||||
        tableControl = maskObj.getDialogControl(table_name);
 | 
			
		||||
        
 | 
			
		||||
        % Добавить новый столбец
 | 
			
		||||
        column = tableControl.addColumn(Name='title', Type='edit');
 | 
			
		||||
        column.Name = title;
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function tab = find_tab_by_name(controls, targetName)
 | 
			
		||||
    tab = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, вкладка ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            tab = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это контейнер — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            tab = find_tab_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(tab)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function container = find_container_by_name(controls, targetName)
 | 
			
		||||
    container = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, контейнер ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Container') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            container = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это вложенный контрол — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            container = find_container_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(container)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function children = get_children(ctrl)
 | 
			
		||||
    if isprop(ctrl, 'DialogControls')
 | 
			
		||||
        children = ctrl.DialogControls;
 | 
			
		||||
    elseif isprop(ctrl, 'Controls')
 | 
			
		||||
        children = ctrl.Controls;
 | 
			
		||||
    elseif isprop(ctrl, 'Children')
 | 
			
		||||
        children = ctrl.Children;
 | 
			
		||||
    else
 | 
			
		||||
        children = [];
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
@ -1,159 +0,0 @@
 | 
			
		||||
clear; clc; close all;
 | 
			
		||||
 | 
			
		||||
model = 'mcu_test_r2023';
 | 
			
		||||
block = [model '/MCU_UPP'];
 | 
			
		||||
 | 
			
		||||
load_system(model);  % если модель ещё не загружена
 | 
			
		||||
 | 
			
		||||
update_mask_from_config(block);
 | 
			
		||||
 | 
			
		||||
disp('Маска обновлена по конфигу.');
 | 
			
		||||
function update_mask_from_config(blockPath)
 | 
			
		||||
    config = load_periph_config();
 | 
			
		||||
    mask = Simulink.Mask.get(blockPath);
 | 
			
		||||
 | 
			
		||||
    tabPrompt = 'Config Peripheral';  % Имя вкладки (Prompt)
 | 
			
		||||
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    tabCtrl = find_tab_by_prompt(allControls, tabPrompt);
 | 
			
		||||
 | 
			
		||||
    if isempty(tabCtrl)
 | 
			
		||||
        error('Вкладка с названием "%s" не найдена в маске', tabPrompt);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Удаляем все контролы внутри вкладки
 | 
			
		||||
    children = tabCtrl.DialogControls;
 | 
			
		||||
    while ~isempty(children)
 | 
			
		||||
        tabCtrl.removeControl(children(1));
 | 
			
		||||
        children = tabCtrl.DialogControls; % обновляем список после удаления
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    periphs = fieldnames(config);
 | 
			
		||||
    for i = 1:numel(periphs)
 | 
			
		||||
        periph = periphs{i};
 | 
			
		||||
        defines = config.(periph).Defines;
 | 
			
		||||
        defNames = fieldnames(defines);
 | 
			
		||||
 | 
			
		||||
        for j = 1:numel(defNames)
 | 
			
		||||
            defPrompt = defNames{j};
 | 
			
		||||
            def = defines.(defPrompt);
 | 
			
		||||
 | 
			
		||||
            % Обрабатываем только checkbox и edit
 | 
			
		||||
            switch lower(def.Type)
 | 
			
		||||
                case 'checkbox'
 | 
			
		||||
                    paramType = 'checkbox';
 | 
			
		||||
                case 'edit'
 | 
			
		||||
                    paramType = 'edit';
 | 
			
		||||
                otherwise
 | 
			
		||||
                    continue;
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            paramName = matlab.lang.makeValidName([periph '_' defPrompt]);
 | 
			
		||||
 | 
			
		||||
            val = def.Default;
 | 
			
		||||
            if islogical(val)
 | 
			
		||||
                if val
 | 
			
		||||
                    valStr = 'on';
 | 
			
		||||
                else
 | 
			
		||||
                    valStr = 'off';
 | 
			
		||||
                end
 | 
			
		||||
            elseif isnumeric(val)
 | 
			
		||||
                valStr = num2str(val);
 | 
			
		||||
            elseif ischar(val)
 | 
			
		||||
                valStr = val;
 | 
			
		||||
            else
 | 
			
		||||
                error('Unsupported default value type for %s.%s', periph, defPrompt);
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            % Добавляем параметр в маску (без TabName)
 | 
			
		||||
            mask.addParameter(...
 | 
			
		||||
                'Type', paramType, ...
 | 
			
		||||
                'Prompt', defPrompt, ...
 | 
			
		||||
                'Name', paramName, ...
 | 
			
		||||
                'Value', valStr, ...
 | 
			
		||||
                'Container', tabPrompt);
 | 
			
		||||
 | 
			
		||||
            disp(['paramType = ', paramType]);
 | 
			
		||||
            disp(['paramName = ', paramName]);
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function config = load_periph_config()
 | 
			
		||||
    jsonText = fileread('periph_config.json');
 | 
			
		||||
    config = jsondecode(jsonText);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function clear_params_from_tab(blockPath, tabPrompt)
 | 
			
		||||
    mask = Simulink.Mask.get(blockPath);
 | 
			
		||||
    controls = mask.getDialogControls;
 | 
			
		||||
    tabs = controls(strcmp({controls.Type}, 'tab'));
 | 
			
		||||
    
 | 
			
		||||
    tabName = '';
 | 
			
		||||
    for i = 1:numel(tabs)
 | 
			
		||||
        if strcmp(tabs(i).Prompt, tabPrompt)
 | 
			
		||||
            tabName = tabs(i).Name; % внутреннее имя вкладки
 | 
			
		||||
            break;
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if isempty(tabName)
 | 
			
		||||
        error('Вкладка с названием "%s" не найдена.', tabPrompt);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Удаляем параметры с TabName == tabName
 | 
			
		||||
    i = 1;
 | 
			
		||||
    while i <= numel(mask.Parameters)
 | 
			
		||||
        if strcmp(mask.Parameters(i).TabName, tabName)
 | 
			
		||||
            mask.removeParameter(i);
 | 
			
		||||
        else
 | 
			
		||||
            i = i + 1;
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% поиск вкладки
 | 
			
		||||
function tab = find_tab_by_name(controls, targetName)
 | 
			
		||||
    tab = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, вкладка ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            tab = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это контейнер — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            tab = find_tab_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(tab)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function children = get_children(ctrl)
 | 
			
		||||
    if isprop(ctrl, 'DialogControls')
 | 
			
		||||
        children = ctrl.DialogControls;
 | 
			
		||||
    elseif isprop(ctrl, 'Controls')
 | 
			
		||||
        children = ctrl.Controls;
 | 
			
		||||
    elseif isprop(ctrl, 'Children')
 | 
			
		||||
        children = ctrl.Children;
 | 
			
		||||
    else
 | 
			
		||||
        children = [];
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										134
									
								
								config_reader.m
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								config_reader.m
									
									
									
									
									
								
							@ -1,134 +0,0 @@
 | 
			
		||||
clear; clc; close all;
 | 
			
		||||
 | 
			
		||||
model = 'mcu_test_r2023';
 | 
			
		||||
block = [model '/MCU_UPP'];
 | 
			
		||||
 | 
			
		||||
load_system(model);  % если модель ещё не загружена
 | 
			
		||||
config = load_periph_config();
 | 
			
		||||
update_mask_from_config(block, config);
 | 
			
		||||
 | 
			
		||||
disp('Маска обновлена по конфигу');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% чтение конфигов
 | 
			
		||||
function config = load_periph_config()
 | 
			
		||||
    jsonText = fileread('periph_config.json');
 | 
			
		||||
    config = jsondecode(jsonText);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
%% запись дефайнов по конфигу
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% обновление маски
 | 
			
		||||
function update_mask_from_config(blockPath, config)
 | 
			
		||||
    mask = Simulink.Mask.get(blockPath);
 | 
			
		||||
 | 
			
		||||
    tabName = 'configTab';  % Имя вкладки (Prompt)
 | 
			
		||||
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    tabCtrl = find_tab_by_name(allControls, tabName);
 | 
			
		||||
 | 
			
		||||
    if isempty(tabCtrl)
 | 
			
		||||
        error('Вкладка с названием "%s" не найдена в маске', tabName);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Удаляем все контролы внутри вкладки
 | 
			
		||||
    children = tabCtrl.DialogControls;
 | 
			
		||||
    while ~isempty(children)
 | 
			
		||||
        mask.removeParameter(children(1).Name);
 | 
			
		||||
        children = tabCtrl.DialogControls; % обновляем список после удаления
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    periphs = fieldnames(config);
 | 
			
		||||
    for i = 1:numel(periphs)
 | 
			
		||||
        periph = periphs{i};
 | 
			
		||||
        defines = config.(periph).Defines;
 | 
			
		||||
        defNames = fieldnames(defines);
 | 
			
		||||
 | 
			
		||||
        for j = 1:numel(defNames)
 | 
			
		||||
            defPrompt = defNames{j};
 | 
			
		||||
            def = defines.(defPrompt);
 | 
			
		||||
 | 
			
		||||
            % Обрабатываем только checkbox и edit
 | 
			
		||||
            switch lower(def.Type)
 | 
			
		||||
                case 'checkbox'
 | 
			
		||||
                    paramType = 'checkbox';
 | 
			
		||||
                case 'edit'
 | 
			
		||||
                    paramType = 'edit';
 | 
			
		||||
                otherwise
 | 
			
		||||
                    continue;
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            paramName = matlab.lang.makeValidName([defPrompt]);
 | 
			
		||||
 | 
			
		||||
            val = def.Default;
 | 
			
		||||
            if islogical(val)
 | 
			
		||||
                if val
 | 
			
		||||
                    valStr = 'on';
 | 
			
		||||
                else
 | 
			
		||||
                    valStr = 'off';
 | 
			
		||||
                end
 | 
			
		||||
            elseif isnumeric(val)
 | 
			
		||||
                valStr = num2str(val);
 | 
			
		||||
            elseif ischar(val)
 | 
			
		||||
                valStr = val;
 | 
			
		||||
            else
 | 
			
		||||
                error('Unsupported default value type for %s.%s', periph, defPrompt);
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            % Добавляем параметр в маску (без TabName)
 | 
			
		||||
            mask.addParameter(...
 | 
			
		||||
                'Type', paramType, ...
 | 
			
		||||
                'Prompt', defPrompt, ...
 | 
			
		||||
                'Name', paramName, ...
 | 
			
		||||
                'Value', valStr, ...
 | 
			
		||||
                'Container', tabName);
 | 
			
		||||
 | 
			
		||||
            param = mask.getParameter(paramName);
 | 
			
		||||
            param.Alias = def.Def;           
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% поиск вкладки
 | 
			
		||||
function tab = find_tab_by_name(controls, targetName)
 | 
			
		||||
    tab = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, вкладка ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            tab = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это контейнер — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            tab = find_tab_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(tab)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function children = get_children(ctrl)
 | 
			
		||||
    if isprop(ctrl, 'DialogControls')
 | 
			
		||||
        children = ctrl.DialogControls;
 | 
			
		||||
    elseif isprop(ctrl, 'Controls')
 | 
			
		||||
        children = ctrl.Controls;
 | 
			
		||||
    elseif isprop(ctrl, 'Children')
 | 
			
		||||
        children = ctrl.Children;
 | 
			
		||||
    else
 | 
			
		||||
        children = [];
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										604
									
								
								mexing.asv
									
									
									
									
									
								
							
							
						
						
									
										604
									
								
								mexing.asv
									
									
									
									
									
								
							@ -1,59 +1,56 @@
 | 
			
		||||
% Компилирует S-function
 | 
			
		||||
clear, clc
 | 
			
		||||
close;
 | 
			
		||||
function mexing(compile_mode)
 | 
			
		||||
    global Ts
 | 
			
		||||
    Ts = 0.00001;
 | 
			
		||||
    
 | 
			
		||||
    if compile_mode == 1
 | 
			
		||||
        delete("*.mexw64")
 | 
			
		||||
        delete("*.mexw64.pdb")
 | 
			
		||||
        delete(".\MCU_Wrapper\Outputs\*.*");
 | 
			
		||||
        set_param(gcb, 'consoleOutput', '');    
 | 
			
		||||
        % Дефайны
 | 
			
		||||
        definesWrapperArg = buildWrapperDefinesString();
 | 
			
		||||
        definesUserArg = parseDefinesMaskText();
 | 
			
		||||
        definesConfigArg = buildConfigDefinesString();
 | 
			
		||||
        definesAllArg = [definesUserArg + " " + definesWrapperArg  + " " + definesConfigArg];    
 | 
			
		||||
            
 | 
			
		||||
Ts = 0.00001;
 | 
			
		||||
        %режимы компиляции
 | 
			
		||||
        if read_checkbox('enableDebug')
 | 
			
		||||
            modeArg = "debug";
 | 
			
		||||
        else
 | 
			
		||||
            modeArg = "release";
 | 
			
		||||
        end    
 | 
			
		||||
        if read_checkbox('fullOutput') || read_checkbox('extConsol') 
 | 
			
		||||
            echoArg = 'echo_enable';
 | 
			
		||||
        else
 | 
			
		||||
            echoArg = 'echo_disable';    
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
delete("*.mexw64")
 | 
			
		||||
delete("*.mexw64.pdb")
 | 
			
		||||
delete(".\MCU_Wrapper\Outputs\*.*");
 | 
			
		||||
set_param(gcb, 'consoleOutput', '');
 | 
			
		||||
        [includesArg, codeArg] = make_mex_arguments('incTable', 'srcTable');
 | 
			
		||||
        
 | 
			
		||||
% Флаг режима отладки
 | 
			
		||||
definesWrapperArg = buildWrapperDefinesString();
 | 
			
		||||
definesUserArg = parseDefinesMaskText();
 | 
			
		||||
definesConfigArg = buildConfigDefinesString();
 | 
			
		||||
definesAllArg = [definesUserArg + " " + definesWrapperArg  + " " + definesConfigArg];    
 | 
			
		||||
        % Вызов батника с двумя параметрами: includes и code
 | 
			
		||||
        cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" %s %s', includesArg, codeArg, definesAllArg, modeArg, echoArg);
 | 
			
		||||
            
 | 
			
		||||
        if read_checkbox('extConsol')
 | 
			
		||||
            cmdout = runBatAndShowOutput(cmd);
 | 
			
		||||
        else
 | 
			
		||||
            [status, cmdout]= system(cmd);
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
if read_checkbox('enableDebug')
 | 
			
		||||
    modeArg = "debug";
 | 
			
		||||
else
 | 
			
		||||
    modeArg = "release";
 | 
			
		||||
        % Сохраним вывод в параметр маски с именем 'consoleOutput'
 | 
			
		||||
        set_param(gcb, 'consoleOutput', cmdout);
 | 
			
		||||
        
 | 
			
		||||
        beep
 | 
			
		||||
    else
 | 
			
		||||
        blockPath = bdroot;
 | 
			
		||||
        config = read_periph_config();
 | 
			
		||||
        config = update_config_from_mask(blockPath, config);
 | 
			
		||||
        write_periph_config(config);
 | 
			
		||||
        update_mask_from_config(blockPath, config);
 | 
			
		||||
        % set_param(gcb, 'consoleOutput', 'Peripheral configuration file loaded. Re-open Block Parameters');
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
if read_checkbox('fullOutput') || read_checkbox('extConsol') 
 | 
			
		||||
    echoArg = 'echo_enable';
 | 
			
		||||
else
 | 
			
		||||
    echoArg = 'echo_disable';
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
[includesArg, codeArg] = make_mex_arguments('incTable', 'srcTable');
 | 
			
		||||
 | 
			
		||||
% Вызов батника с двумя параметрами: includes и code
 | 
			
		||||
cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" %s %s', includesArg, codeArg, definesAllArg, modeArg, echoArg);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if read_checkbox('extConsol')
 | 
			
		||||
    cmdout = runBatAndShowOutput(cmd);
 | 
			
		||||
else
 | 
			
		||||
    [status, cmdout]= system(cmd);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
% Сохраним вывод в параметр маски с именем 'consoleOutput'
 | 
			
		||||
set_param(gcb, 'consoleOutput', cmdout);
 | 
			
		||||
 | 
			
		||||
% % Обновим Mask Display для показа
 | 
			
		||||
% maskDisplayStr = sprintf('disp(''%s'')', cmdout);
 | 
			
		||||
% set_param(gcb, 'MaskDisplay', maskDisplayStr);
 | 
			
		||||
 | 
			
		||||
beep
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% COMPILE PARAMS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -103,45 +100,11 @@ function definesWrapperArg = buildWrapperDefinesString()
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'enableDeinit', 0);
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'threadCycles', 1);
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'mcuClk', 1);
 | 
			
		||||
 | 
			
		||||
    % blockHandle = gcbh;
 | 
			
		||||
    % 
 | 
			
		||||
    % % Получаем MaskValues и MaskNames
 | 
			
		||||
    % maskValues = get_param(blockHandle, 'MaskValues');
 | 
			
		||||
    % paramNames = get_param(blockHandle, 'MaskNames');
 | 
			
		||||
    % 
 | 
			
		||||
    % % Индексы параметров
 | 
			
		||||
    % idxCycles = find(strcmp(paramNames, 'threadCycles'));
 | 
			
		||||
    % idxClk    = find(strcmp(paramNames, 'mcuClk'));
 | 
			
		||||
    % 
 | 
			
		||||
    % % Значения
 | 
			
		||||
    % cyclesVal = maskValues{idxCycles};
 | 
			
		||||
    % clkMHz    = str2double(maskValues{idxClk});
 | 
			
		||||
    % clkHz     = round(clkMHz * 1e6);
 | 
			
		||||
    % 
 | 
			
		||||
    % % Формируем defines в формате: -D"NAME=VALUE"
 | 
			
		||||
    % if read_checkbox('enableThreading')
 | 
			
		||||
    %     def1 = ['-D"RUN_APP_MAIN_FUNC_THREAD"'];
 | 
			
		||||
    % else
 | 
			
		||||
    %     def1 = [''];
 | 
			
		||||
    % end
 | 
			
		||||
    % 
 | 
			
		||||
    % if read_checkbox('enableDeinit')
 | 
			
		||||
    %     def2 = ['-D"DEINITIALIZE_AFTER_SIM"'];
 | 
			
		||||
    % else
 | 
			
		||||
    %     def2 = [''];
 | 
			
		||||
    % end
 | 
			
		||||
    % 
 | 
			
		||||
    % def3 = ['-D"DEKSTOP_CYCLES_FOR_MCU_APP__EQ__' cyclesVal '"'];
 | 
			
		||||
    % def4 = ['-D"MCU_CORE_CLOCK__EQ__' num2str(clkHz) '"'];
 | 
			
		||||
    % 
 | 
			
		||||
    % definesWrapperArg = strjoin({def1, def2, def3, def4}, ' ');
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function definesUserArg = parseDefinesMaskText()
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
 | 
			
		||||
    % Получаем MaskValues и MaskNames
 | 
			
		||||
    maskValues = get_param(blockHandle, 'MaskValues');
 | 
			
		||||
    paramNames = get_param(blockHandle, 'MaskNames');
 | 
			
		||||
@ -195,65 +158,42 @@ function definesWrapperArg = buildConfigDefinesString()
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
    mask = Simulink.Mask.get(blockHandle);
 | 
			
		||||
 | 
			
		||||
    tabName = 'configTab';  % Имя вкладки (Prompt)
 | 
			
		||||
    tabName = 'configTabAll';  % Имя вкладки (Prompt)
 | 
			
		||||
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    tabCtrl = find_tab_by_name(allControls, tabName);
 | 
			
		||||
    tabCtrl = find_container_by_name(allControls, tabName);
 | 
			
		||||
 | 
			
		||||
    if isempty(tabCtrl)
 | 
			
		||||
        error('Вкладка с названием "%s" не найдена в маске', tabName);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    collect_all_parameters
 | 
			
		||||
 | 
			
		||||
    definesWrapperArg = '';
 | 
			
		||||
 | 
			
		||||
    % Получаем все контролы внутри вкладки
 | 
			
		||||
    children = tabCtrl.DialogControls;
 | 
			
		||||
    for i = 1:numel(children)
 | 
			
		||||
        ctrl = children(i);
 | 
			
		||||
isprop(ctrl, 'Type')
 | 
			
		||||
isprop(ctrl, 'Name')
 | 
			
		||||
        if isprop(ctrl, 'Type') && isprop(ctrl, 'Name')
 | 
			
		||||
            switch lower(ctrl.Type)
 | 
			
		||||
                case 'checkbox'
 | 
			
		||||
                    definesWrapperArg = addDefineByParam(definesWrapperArg, ctrl.ParameterName, 0);
 | 
			
		||||
                case 'edit'
 | 
			
		||||
                    definesWrapperArg = addDefineByParam(definesWrapperArg, ctrl.ParameterName, 1);
 | 
			
		||||
                otherwise
 | 
			
		||||
                    % Пропускаем другие типы
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
        % Получаем имя параметра из контрола
 | 
			
		||||
        paramName = ctrl.Name;
 | 
			
		||||
            try
 | 
			
		||||
                % Получаем объект параметра по имени
 | 
			
		||||
                param = mask.getParameter(paramName);
 | 
			
		||||
    
 | 
			
		||||
    % blockHandle = gcbh;
 | 
			
		||||
    % 
 | 
			
		||||
    % % Получаем MaskValues и MaskNames
 | 
			
		||||
    % maskValues = get_param(blockHandle, 'MaskValues');
 | 
			
		||||
    % paramNames = get_param(blockHandle, 'MaskNames');
 | 
			
		||||
    % 
 | 
			
		||||
    % % Индексы параметров
 | 
			
		||||
    % idxCycles = find(strcmp(paramNames, 'threadCycles'));
 | 
			
		||||
    % idxClk    = find(strcmp(paramNames, 'mcuClk'));
 | 
			
		||||
    % 
 | 
			
		||||
    % % Значения
 | 
			
		||||
    % cyclesVal = maskValues{idxCycles};
 | 
			
		||||
    % clkMHz    = str2double(maskValues{idxClk});
 | 
			
		||||
    % clkHz     = round(clkMHz * 1e6);
 | 
			
		||||
    % 
 | 
			
		||||
    % % Формируем defines в формате: -D"NAME=VALUE"
 | 
			
		||||
    % if read_checkbox('enableThreading')
 | 
			
		||||
    %     def1 = ['-D"RUN_APP_MAIN_FUNC_THREAD"'];
 | 
			
		||||
    % else
 | 
			
		||||
    %     def1 = [''];
 | 
			
		||||
    % end
 | 
			
		||||
    % 
 | 
			
		||||
    % if read_checkbox('enableDeinit')
 | 
			
		||||
    %     def2 = ['-D"DEINITIALIZE_AFTER_SIM"'];
 | 
			
		||||
    % else
 | 
			
		||||
    %     def2 = [''];
 | 
			
		||||
    % end
 | 
			
		||||
    % 
 | 
			
		||||
    % def3 = ['-D"DEKSTOP_CYCLES_FOR_MCU_APP__EQ__' cyclesVal '"'];
 | 
			
		||||
    % def4 = ['-D"MCU_CORE_CLOCK__EQ__' num2str(clkHz) '"'];
 | 
			
		||||
    % 
 | 
			
		||||
    % definesWrapperArg = strjoin({def1, def2, def3, def4}, ' ');
 | 
			
		||||
                % Определяем тип параметра
 | 
			
		||||
                switch lower(param.Type)
 | 
			
		||||
                    case 'checkbox'
 | 
			
		||||
                        definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0);
 | 
			
		||||
                    case 'edit'
 | 
			
		||||
                        definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1);
 | 
			
		||||
                    otherwise
 | 
			
		||||
                        % Необрабатываемые типы
 | 
			
		||||
                end
 | 
			
		||||
            catch ME
 | 
			
		||||
                % warning('Не удалось получить параметр "%s": %s', paramName, ME.message);
 | 
			
		||||
            end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -344,42 +284,6 @@ function checkbox_state = read_checkbox(checkboxName)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function tab = find_tab_by_name(controls, targetName)
 | 
			
		||||
    tab = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, вкладка ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            tab = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это контейнер — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            tab = find_tab_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(tab)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function children = get_children(ctrl)
 | 
			
		||||
    if isprop(ctrl, 'DialogControls')
 | 
			
		||||
        children = ctrl.DialogControls;
 | 
			
		||||
    elseif isprop(ctrl, 'Controls')
 | 
			
		||||
        children = ctrl.Controls;
 | 
			
		||||
    elseif isprop(ctrl, 'Children')
 | 
			
		||||
        children = ctrl.Children;
 | 
			
		||||
    else
 | 
			
		||||
        children = [];
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
%% CONSOLE FUNCTIONS
 | 
			
		||||
 | 
			
		||||
function cmdret = runBatAndShowOutput(cmd)
 | 
			
		||||
@ -456,3 +360,375 @@ function logWindow_append(line)
 | 
			
		||||
    jTextArea.setCaretPosition(jTextArea.getDocument.getLength);
 | 
			
		||||
    drawnow;
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% READ CONFIGS
 | 
			
		||||
function config = read_periph_config()
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
    mask = Simulink.Mask.get(blockHandle);
 | 
			
		||||
 | 
			
		||||
    pathparam = mask.getParameter('periphPath');
 | 
			
		||||
    config_path = pathparam.Value;
 | 
			
		||||
 | 
			
		||||
    jsonText = fileread(config_path);
 | 
			
		||||
    config = jsondecode(jsonText);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function write_periph_config(config)
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
    mask = Simulink.Mask.get(blockHandle);
 | 
			
		||||
 | 
			
		||||
    pathparam = mask.getParameter('periphPath');
 | 
			
		||||
    config_path = pathparam.Value;
 | 
			
		||||
 | 
			
		||||
    jsonText = jsonencode(config, 'PrettyPrint', true);
 | 
			
		||||
    fid = fopen(config_path, 'w');
 | 
			
		||||
    if fid == -1
 | 
			
		||||
        error('Не удалось открыть файл periph_config.json для записи.');
 | 
			
		||||
    end
 | 
			
		||||
    fwrite(fid, jsonText, 'char');
 | 
			
		||||
    fclose(fid);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
%% CONFIG MASK TOOLS
 | 
			
		||||
function update_mask_from_config(blockPath, config)
 | 
			
		||||
    blockPath = [blockPath '/MCU'];
 | 
			
		||||
 | 
			
		||||
    % Проверяем, была ли маска открыта
 | 
			
		||||
    wasOpen = isMaskDialogOpen(blockPath);
 | 
			
		||||
    close_system(blockPath, 0);
 | 
			
		||||
    mask = Simulink.Mask.get(blockPath);
 | 
			
		||||
    
 | 
			
		||||
    tableNames = {'incTable', 'srcTable'};
 | 
			
		||||
    columns_backup = clear_tables(blockPath, tableNames);
 | 
			
		||||
 | 
			
		||||
    containerName = 'configTabAll';
 | 
			
		||||
    clear_all_from_container(mask, containerName);
 | 
			
		||||
 | 
			
		||||
    % Ищем контейнер, в который будем добавлять вкладки
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    container = find_container_by_name(allControls, containerName);
 | 
			
		||||
    if isempty(container)
 | 
			
		||||
        error('Контейнер "%s" не найден в маске.', containerName);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Проходим по каждому модулю (ADC, TIM...)
 | 
			
		||||
    periphs = fieldnames(config);
 | 
			
		||||
    for i = 1:numel(periphs)
 | 
			
		||||
        periph = periphs{i};
 | 
			
		||||
        defines = config.(periph).Defines;
 | 
			
		||||
        defNames = fieldnames(defines);
 | 
			
		||||
 | 
			
		||||
        % Создаём вкладку для модуля
 | 
			
		||||
        tabCtrl = container.addDialogControl('tab', periph);
 | 
			
		||||
        tabCtrl.Prompt = [periph ' Config'];
 | 
			
		||||
 | 
			
		||||
        for j = 1:numel(defNames)
 | 
			
		||||
            defPrompt = defNames{j};
 | 
			
		||||
            def = defines.(defPrompt);
 | 
			
		||||
            prompt = def.Prompt;
 | 
			
		||||
 | 
			
		||||
            % Только checkbox и edit
 | 
			
		||||
            switch lower(def.Type)
 | 
			
		||||
                case 'checkbox'
 | 
			
		||||
                    paramType = 'checkbox';
 | 
			
		||||
                case 'edit'
 | 
			
		||||
                    paramType = 'edit';
 | 
			
		||||
                otherwise
 | 
			
		||||
                    continue;
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            paramName = matlab.lang.makeValidName(defPrompt);
 | 
			
		||||
 | 
			
		||||
            % Преобразуем значение по типу
 | 
			
		||||
            val = def.Default;
 | 
			
		||||
            if islogical(val)
 | 
			
		||||
                if val
 | 
			
		||||
                    valStr = 'on';
 | 
			
		||||
                else
 | 
			
		||||
                    valStr = 'off';
 | 
			
		||||
                end
 | 
			
		||||
            elseif isnumeric(val)
 | 
			
		||||
                valStr = num2str(val);
 | 
			
		||||
            elseif ischar(val)
 | 
			
		||||
                valStr = val;
 | 
			
		||||
            else
 | 
			
		||||
                error('Unsupported default value type for %s.%s', periph, defPrompt);
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            % Добавляем параметр в соответствующую вкладку
 | 
			
		||||
            param = mask.addParameter( ...
 | 
			
		||||
                'Type', paramType, ...
 | 
			
		||||
                'Prompt', prompt, ...
 | 
			
		||||
                'Name', paramName, ...
 | 
			
		||||
                'Value', valStr, ...
 | 
			
		||||
                'Container', periph ...
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            param.Alias = def.Def;
 | 
			
		||||
            if def.NewRow
 | 
			
		||||
                row_param = 'new';
 | 
			
		||||
            else
 | 
			
		||||
                row_param = 'current';
 | 
			
		||||
            end
 | 
			
		||||
            param.DialogControl.Row = row_param;
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Восстанавливаем таблицы
 | 
			
		||||
    restore_tables(blockPath, tableNames, columns_backup);
 | 
			
		||||
 | 
			
		||||
    % Повторно открываем маску, если она была открыта
 | 
			
		||||
    if wasOpen
 | 
			
		||||
        open_system(blockPath, 'mask');
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function config = update_config_from_mask(blockPath, config)
 | 
			
		||||
    blockPath = [blockPath '/MCU'];
 | 
			
		||||
    mask = Simulink.Mask.get(blockPath);
 | 
			
		||||
 | 
			
		||||
    periphs = fieldnames(config);
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(periphs)
 | 
			
		||||
        periph = periphs{i};
 | 
			
		||||
        defines = config.(periph).Defines;
 | 
			
		||||
        defNames = fieldnames(defines);
 | 
			
		||||
 | 
			
		||||
        for j = 1:numel(defNames)
 | 
			
		||||
            defPrompt = defNames{j};
 | 
			
		||||
            paramName = matlab.lang.makeValidName(defPrompt);
 | 
			
		||||
            param = mask.getParameter(paramName);
 | 
			
		||||
 | 
			
		||||
            % Получаем значение из маски и сохраняем в конфиг
 | 
			
		||||
            valStr = param.Value;
 | 
			
		||||
 | 
			
		||||
            % Преобразуем строку в соответствующий тип
 | 
			
		||||
            if strcmpi(defines.(defPrompt).Type, 'checkbox')
 | 
			
		||||
                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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function clear_all_from_container(mask, containerName)
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    container = find_container_by_name(allControls, containerName);
 | 
			
		||||
    if isempty(container)
 | 
			
		||||
        warning('Контейнер "%s" не найден.', containerName);
 | 
			
		||||
        return;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Рекурсивно собрать все параметры (не вкладки)
 | 
			
		||||
    paramsToDelete = collect_all_parameters(container);
 | 
			
		||||
 | 
			
		||||
    % Удаляем все параметры
 | 
			
		||||
    for i = 1:numel(paramsToDelete)
 | 
			
		||||
        try
 | 
			
		||||
            mask.removeParameter(paramsToDelete{i});
 | 
			
		||||
        catch
 | 
			
		||||
            warning('Не удалось удалить параметр %s', paramsToDelete{i});
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Рекурсивно удалить все вкладки внутри контейнера
 | 
			
		||||
    delete_all_tabs(mask, container);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function params = collect_all_parameters(container)
 | 
			
		||||
    params = {};
 | 
			
		||||
    children = container.DialogControls;
 | 
			
		||||
    for i = 1:numel(children)
 | 
			
		||||
        ctrl = children(i);
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab')
 | 
			
		||||
            % Если вкладка — рекурсивно собираем параметры внутри неё
 | 
			
		||||
            params = [params, collect_all_parameters(ctrl)];
 | 
			
		||||
        else
 | 
			
		||||
            % Иначе это параметр — добавляем имя
 | 
			
		||||
            params{end+1} = ctrl.Name; %#ok<AGROW>
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function delete_all_tabs(mask, container)
 | 
			
		||||
    children = container.DialogControls;
 | 
			
		||||
    % Идём в обратном порядке, чтобы безопасно удалять
 | 
			
		||||
    for i = numel(children):-1:1
 | 
			
		||||
        ctrl = children(i);
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab')
 | 
			
		||||
            % Сначала рекурсивно удаляем вкладки внутри текущей вкладки
 | 
			
		||||
            delete_all_tabs(mask, ctrl);
 | 
			
		||||
            try
 | 
			
		||||
                container.removeDialogControl(ctrl.Name);
 | 
			
		||||
            catch ME
 | 
			
		||||
                warning('Не удалось удалить вкладку %s: %s', ctrl.Name, ME.message);
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function isOpen = isMaskDialogOpen(blockPath)
 | 
			
		||||
    isOpen = false;
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
        % Получаем имя блока
 | 
			
		||||
        blockName = get_param(blockPath, 'Name');
 | 
			
		||||
 | 
			
		||||
        % Получаем список окон MATLAB GUI
 | 
			
		||||
        jWindows = java.awt.Window.getWindows();
 | 
			
		||||
 | 
			
		||||
        for i = 1:numel(jWindows)
 | 
			
		||||
            win = jWindows(i);
 | 
			
		||||
 | 
			
		||||
            % Проверка, что окно видимое и активно
 | 
			
		||||
            if win.isShowing()
 | 
			
		||||
                try
 | 
			
		||||
                    title = char(win.getTitle());
 | 
			
		||||
                    % Проверка по ключевому слову, соответствующему заголовку маски
 | 
			
		||||
                    if contains(title, ['Mask Editor: ' blockName]) || ...
 | 
			
		||||
                       contains(title, ['Mask: ' blockName]) || ...
 | 
			
		||||
                       contains(title, blockName)
 | 
			
		||||
                        isOpen = true;
 | 
			
		||||
                        return;
 | 
			
		||||
                    end
 | 
			
		||||
                catch
 | 
			
		||||
                    % Окно не имеет заголовка — пропускаем
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    catch
 | 
			
		||||
        isOpen = false;
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function column_titles = clear_tables(block, table_names)
 | 
			
		||||
    % Очищает столбцы в каждой таблице из массива имен table_names
 | 
			
		||||
    % Возвращает cell-массив с названиями первых столбцов каждой таблицы
 | 
			
		||||
    
 | 
			
		||||
    % Получить объект маски блока
 | 
			
		||||
    maskObj = Simulink.Mask.get(block);
 | 
			
		||||
    
 | 
			
		||||
    % Инициализировать cell-массив для хранения названий столбцов
 | 
			
		||||
    column_titles = cell(size(table_names));
 | 
			
		||||
    
 | 
			
		||||
    for k = 1:numel(table_names)
 | 
			
		||||
        table_name = table_names{k};
 | 
			
		||||
        
 | 
			
		||||
        % Получить объект управления таблицей
 | 
			
		||||
        tableControl = maskObj.getDialogControl(table_name);
 | 
			
		||||
        
 | 
			
		||||
        % Получить количество столбцов
 | 
			
		||||
        nCols = tableControl.getNumberOfColumns;
 | 
			
		||||
        
 | 
			
		||||
        if nCols > 0
 | 
			
		||||
            % Получить первый столбец (который будем удалять)
 | 
			
		||||
            column = tableControl.getColumn(1);
 | 
			
		||||
            column_titles{k} = column.Name;
 | 
			
		||||
            
 | 
			
		||||
            % Удаляем все столбцы
 | 
			
		||||
            % Важно: при удалении столбцов индексы меняются, 
 | 
			
		||||
            % поэтому удаляем всегда первый столбец nCols раз
 | 
			
		||||
            for i = 1:nCols
 | 
			
		||||
                tableControl.removeColumn(1);
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            % Если столбцов нет, возвращаем пустую строку
 | 
			
		||||
            column_titles{k} = '';
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function restore_tables(block, table_names, column_titles)
 | 
			
		||||
    % Восстанавливает первый столбец в каждой таблице из массива имен
 | 
			
		||||
    % Использует массив column_titles для установки имени столбца
 | 
			
		||||
    
 | 
			
		||||
    % Получить объект маски блока
 | 
			
		||||
    maskObj = Simulink.Mask.get(block);
 | 
			
		||||
    
 | 
			
		||||
    for k = 1:numel(table_names)
 | 
			
		||||
        table_name = table_names{k};
 | 
			
		||||
        title = column_titles{k};
 | 
			
		||||
        
 | 
			
		||||
        % Получить объект управления таблицей
 | 
			
		||||
        tableControl = maskObj.getDialogControl(table_name);
 | 
			
		||||
        
 | 
			
		||||
        % Добавить новый столбец
 | 
			
		||||
        column = tableControl.addColumn(Name='title', Type='edit');
 | 
			
		||||
        column.Name = title;
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function tab = find_tab_by_name(controls, targetName)
 | 
			
		||||
    tab = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, вкладка ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            tab = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это контейнер — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            tab = find_tab_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(tab)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function container = find_container_by_name(controls, targetName)
 | 
			
		||||
    container = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, контейнер ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Container') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            container = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это вложенный контрол — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            container = find_container_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(container)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function children = get_children(ctrl)
 | 
			
		||||
    if isprop(ctrl, 'DialogControls')
 | 
			
		||||
        children = ctrl.DialogControls;
 | 
			
		||||
    elseif isprop(ctrl, 'Controls')
 | 
			
		||||
        children = ctrl.Controls;
 | 
			
		||||
    elseif isprop(ctrl, 'Children')
 | 
			
		||||
        children = ctrl.Children;
 | 
			
		||||
    else
 | 
			
		||||
        children = [];
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										616
									
								
								mexing.m
									
									
									
									
									
								
							
							
						
						
									
										616
									
								
								mexing.m
									
									
									
									
									
								
							@ -1,59 +1,56 @@
 | 
			
		||||
% Компилирует S-function
 | 
			
		||||
clear, clc
 | 
			
		||||
close;
 | 
			
		||||
function mexing(compile_mode)
 | 
			
		||||
    global Ts
 | 
			
		||||
    Ts = 0.00001;
 | 
			
		||||
    
 | 
			
		||||
    if compile_mode == 1
 | 
			
		||||
        delete("*.mexw64")
 | 
			
		||||
        delete("*.mexw64.pdb")
 | 
			
		||||
        delete(".\MCU_Wrapper\Outputs\*.*");
 | 
			
		||||
        set_param(gcb, 'consoleOutput', '');    
 | 
			
		||||
        % Дефайны
 | 
			
		||||
        definesWrapperArg = buildWrapperDefinesString();
 | 
			
		||||
        definesUserArg = parseDefinesMaskText();
 | 
			
		||||
        definesConfigArg = buildConfigDefinesString();
 | 
			
		||||
        definesAllArg = [definesUserArg + " " + definesWrapperArg  + " " + definesConfigArg];    
 | 
			
		||||
            
 | 
			
		||||
Ts = 0.00001;
 | 
			
		||||
        %режимы компиляции
 | 
			
		||||
        if read_checkbox('enableDebug')
 | 
			
		||||
            modeArg = "debug";
 | 
			
		||||
        else
 | 
			
		||||
            modeArg = "release";
 | 
			
		||||
        end    
 | 
			
		||||
        if read_checkbox('fullOutput') || read_checkbox('extConsol') 
 | 
			
		||||
            echoArg = 'echo_enable';
 | 
			
		||||
        else
 | 
			
		||||
            echoArg = 'echo_disable';    
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
delete("*.mexw64")
 | 
			
		||||
delete("*.mexw64.pdb")
 | 
			
		||||
delete(".\MCU_Wrapper\Outputs\*.*");
 | 
			
		||||
set_param(gcb, 'consoleOutput', '');
 | 
			
		||||
        [includesArg, codeArg] = make_mex_arguments('incTable', 'srcTable');
 | 
			
		||||
        
 | 
			
		||||
% Флаг режима отладки
 | 
			
		||||
definesWrapperArg = buildWrapperDefinesString();
 | 
			
		||||
definesUserArg = parseDefinesMaskText();
 | 
			
		||||
definesConfigArg = buildConfigDefinesString();
 | 
			
		||||
definesAllArg = [definesUserArg + " " + definesWrapperArg  + " " + definesConfigArg];    
 | 
			
		||||
        % Вызов батника с двумя параметрами: includes и code
 | 
			
		||||
        cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" %s %s', includesArg, codeArg, definesAllArg, modeArg, echoArg);
 | 
			
		||||
            
 | 
			
		||||
        if read_checkbox('extConsol')
 | 
			
		||||
            cmdout = runBatAndShowOutput(cmd);
 | 
			
		||||
        else
 | 
			
		||||
            [status, cmdout]= system(cmd);
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
if read_checkbox('enableDebug')
 | 
			
		||||
    modeArg = "debug";
 | 
			
		||||
else
 | 
			
		||||
    modeArg = "release";
 | 
			
		||||
        % Сохраним вывод в параметр маски с именем 'consoleOutput'
 | 
			
		||||
        set_param(gcb, 'consoleOutput', cmdout);
 | 
			
		||||
        
 | 
			
		||||
        beep
 | 
			
		||||
    else
 | 
			
		||||
        blockPath = bdroot;
 | 
			
		||||
        config = read_periph_config();
 | 
			
		||||
        config = update_config_from_mask(blockPath, config);
 | 
			
		||||
        write_periph_config(config);
 | 
			
		||||
        update_mask_from_config(blockPath, config);
 | 
			
		||||
        % set_param(gcb, 'consoleOutput', 'Peripheral configuration file loaded. Re-open Block Parameters');
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
if read_checkbox('fullOutput') || read_checkbox('extConsol') 
 | 
			
		||||
    echoArg = 'echo_enable';
 | 
			
		||||
else
 | 
			
		||||
    echoArg = 'echo_disable';
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
[includesArg, codeArg] = make_mex_arguments('incTable', 'srcTable');
 | 
			
		||||
 | 
			
		||||
% Вызов батника с двумя параметрами: includes и code
 | 
			
		||||
cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" %s %s', includesArg, codeArg, definesAllArg, modeArg, echoArg);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if read_checkbox('extConsol')
 | 
			
		||||
    cmdout = runBatAndShowOutput(cmd);
 | 
			
		||||
else
 | 
			
		||||
    [status, cmdout]= system(cmd);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
% Сохраним вывод в параметр маски с именем 'consoleOutput'
 | 
			
		||||
set_param(gcb, 'consoleOutput', cmdout);
 | 
			
		||||
 | 
			
		||||
% % Обновим Mask Display для показа
 | 
			
		||||
% maskDisplayStr = sprintf('disp(''%s'')', cmdout);
 | 
			
		||||
% set_param(gcb, 'MaskDisplay', maskDisplayStr);
 | 
			
		||||
 | 
			
		||||
beep
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% COMPILE PARAMS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -103,45 +100,11 @@ function definesWrapperArg = buildWrapperDefinesString()
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'enableDeinit', 0);
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'threadCycles', 1);
 | 
			
		||||
    definesWrapperArg = addDefineByParam(definesWrapperArg, 'mcuClk', 1);
 | 
			
		||||
 | 
			
		||||
    % blockHandle = gcbh;
 | 
			
		||||
    % 
 | 
			
		||||
    % % Получаем MaskValues и MaskNames
 | 
			
		||||
    % maskValues = get_param(blockHandle, 'MaskValues');
 | 
			
		||||
    % paramNames = get_param(blockHandle, 'MaskNames');
 | 
			
		||||
    % 
 | 
			
		||||
    % % Индексы параметров
 | 
			
		||||
    % idxCycles = find(strcmp(paramNames, 'threadCycles'));
 | 
			
		||||
    % idxClk    = find(strcmp(paramNames, 'mcuClk'));
 | 
			
		||||
    % 
 | 
			
		||||
    % % Значения
 | 
			
		||||
    % cyclesVal = maskValues{idxCycles};
 | 
			
		||||
    % clkMHz    = str2double(maskValues{idxClk});
 | 
			
		||||
    % clkHz     = round(clkMHz * 1e6);
 | 
			
		||||
    % 
 | 
			
		||||
    % % Формируем defines в формате: -D"NAME=VALUE"
 | 
			
		||||
    % if read_checkbox('enableThreading')
 | 
			
		||||
    %     def1 = ['-D"RUN_APP_MAIN_FUNC_THREAD"'];
 | 
			
		||||
    % else
 | 
			
		||||
    %     def1 = [''];
 | 
			
		||||
    % end
 | 
			
		||||
    % 
 | 
			
		||||
    % if read_checkbox('enableDeinit')
 | 
			
		||||
    %     def2 = ['-D"DEINITIALIZE_AFTER_SIM"'];
 | 
			
		||||
    % else
 | 
			
		||||
    %     def2 = [''];
 | 
			
		||||
    % end
 | 
			
		||||
    % 
 | 
			
		||||
    % def3 = ['-D"DEKSTOP_CYCLES_FOR_MCU_APP__EQ__' cyclesVal '"'];
 | 
			
		||||
    % def4 = ['-D"MCU_CORE_CLOCK__EQ__' num2str(clkHz) '"'];
 | 
			
		||||
    % 
 | 
			
		||||
    % definesWrapperArg = strjoin({def1, def2, def3, def4}, ' ');
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function definesUserArg = parseDefinesMaskText()
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
 | 
			
		||||
    % Получаем MaskValues и MaskNames
 | 
			
		||||
    maskValues = get_param(blockHandle, 'MaskValues');
 | 
			
		||||
    paramNames = get_param(blockHandle, 'MaskNames');
 | 
			
		||||
@ -195,71 +158,38 @@ function definesWrapperArg = buildConfigDefinesString()
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
    mask = Simulink.Mask.get(blockHandle);
 | 
			
		||||
 | 
			
		||||
    tabName = 'configTab';  % Имя вкладки (Prompt)
 | 
			
		||||
    tabName = 'configTabAll';  % Имя вкладки (Prompt)
 | 
			
		||||
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    tabCtrl = find_tab_by_name(allControls, tabName);
 | 
			
		||||
    tabCtrl = find_container_by_name(allControls, tabName);
 | 
			
		||||
 | 
			
		||||
    if isempty(tabCtrl)
 | 
			
		||||
        error('Вкладка с названием "%s" не найдена в маске', tabName);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    params = collect_all_parameters(tabCtrl);
 | 
			
		||||
    definesWrapperArg = '';
 | 
			
		||||
    % Получаем все контролы внутри вкладки
 | 
			
		||||
    children = tabCtrl.DialogControls;
 | 
			
		||||
    for i = 1:numel(children)
 | 
			
		||||
        ctrl = children(i);
 | 
			
		||||
    for i = 1:numel(params)
 | 
			
		||||
        % Получаем имя параметра из контрола
 | 
			
		||||
        paramName = ctrl.Name;
 | 
			
		||||
            try
 | 
			
		||||
                % Получаем объект параметра по имени
 | 
			
		||||
                param = mask.getParameter(paramName);
 | 
			
		||||
        paramName = string(params(i));
 | 
			
		||||
        try
 | 
			
		||||
            % Получаем объект параметра по имени
 | 
			
		||||
            param = mask.getParameter(paramName);
 | 
			
		||||
 | 
			
		||||
                % Определяем тип параметра
 | 
			
		||||
                switch lower(param.Type)
 | 
			
		||||
                    case 'checkbox'
 | 
			
		||||
                        definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0);
 | 
			
		||||
                    case 'edit'
 | 
			
		||||
                        definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1);
 | 
			
		||||
                    otherwise
 | 
			
		||||
                        % Необрабатываемые типы
 | 
			
		||||
                end
 | 
			
		||||
            catch ME
 | 
			
		||||
                warning('Не удалось получить параметр "%s": %s', paramName, ME.message);
 | 
			
		||||
            % Определяем тип параметра
 | 
			
		||||
            switch lower(param.Type)
 | 
			
		||||
                case 'checkbox'
 | 
			
		||||
                    definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0);
 | 
			
		||||
                case 'edit'
 | 
			
		||||
                    definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1);
 | 
			
		||||
                otherwise
 | 
			
		||||
                    % Необрабатываемые типы
 | 
			
		||||
            end
 | 
			
		||||
        catch ME
 | 
			
		||||
            % warning('Не удалось получить параметр "%s": %s', paramName, ME.message);
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % blockHandle = gcbh;
 | 
			
		||||
    % 
 | 
			
		||||
    % % Получаем MaskValues и MaskNames
 | 
			
		||||
    % maskValues = get_param(blockHandle, 'MaskValues');
 | 
			
		||||
    % paramNames = get_param(blockHandle, 'MaskNames');
 | 
			
		||||
    % 
 | 
			
		||||
    % % Индексы параметров
 | 
			
		||||
    % idxCycles = find(strcmp(paramNames, 'threadCycles'));
 | 
			
		||||
    % idxClk    = find(strcmp(paramNames, 'mcuClk'));
 | 
			
		||||
    % 
 | 
			
		||||
    % % Значения
 | 
			
		||||
    % cyclesVal = maskValues{idxCycles};
 | 
			
		||||
    % clkMHz    = str2double(maskValues{idxClk});
 | 
			
		||||
    % clkHz     = round(clkMHz * 1e6);
 | 
			
		||||
    % 
 | 
			
		||||
    % % Формируем defines в формате: -D"NAME=VALUE"
 | 
			
		||||
    % if read_checkbox('enableThreading')
 | 
			
		||||
    %     def1 = ['-D"RUN_APP_MAIN_FUNC_THREAD"'];
 | 
			
		||||
    % else
 | 
			
		||||
    %     def1 = [''];
 | 
			
		||||
    % end
 | 
			
		||||
    % 
 | 
			
		||||
    % if read_checkbox('enableDeinit')
 | 
			
		||||
    %     def2 = ['-D"DEINITIALIZE_AFTER_SIM"'];
 | 
			
		||||
    % else
 | 
			
		||||
    %     def2 = [''];
 | 
			
		||||
    % end
 | 
			
		||||
    % 
 | 
			
		||||
    % def3 = ['-D"DEKSTOP_CYCLES_FOR_MCU_APP__EQ__' cyclesVal '"'];
 | 
			
		||||
    % def4 = ['-D"MCU_CORE_CLOCK__EQ__' num2str(clkHz) '"'];
 | 
			
		||||
    % 
 | 
			
		||||
    % definesWrapperArg = strjoin({def1, def2, def3, def4}, ' ');
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -350,42 +280,6 @@ function checkbox_state = read_checkbox(checkboxName)
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function tab = find_tab_by_name(controls, targetName)
 | 
			
		||||
    tab = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, вкладка ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            tab = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это контейнер — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            tab = find_tab_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(tab)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function children = get_children(ctrl)
 | 
			
		||||
    if isprop(ctrl, 'DialogControls')
 | 
			
		||||
        children = ctrl.DialogControls;
 | 
			
		||||
    elseif isprop(ctrl, 'Controls')
 | 
			
		||||
        children = ctrl.Controls;
 | 
			
		||||
    elseif isprop(ctrl, 'Children')
 | 
			
		||||
        children = ctrl.Children;
 | 
			
		||||
    else
 | 
			
		||||
        children = [];
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
%% CONSOLE FUNCTIONS
 | 
			
		||||
 | 
			
		||||
function cmdret = runBatAndShowOutput(cmd)
 | 
			
		||||
@ -462,3 +356,383 @@ function logWindow_append(line)
 | 
			
		||||
    jTextArea.setCaretPosition(jTextArea.getDocument.getLength);
 | 
			
		||||
    drawnow;
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%% READ CONFIGS
 | 
			
		||||
function config = read_periph_config()
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
    mask = Simulink.Mask.get(blockHandle);
 | 
			
		||||
 | 
			
		||||
    pathparam = mask.getParameter('periphPath');
 | 
			
		||||
    config_path = pathparam.Value;
 | 
			
		||||
 | 
			
		||||
    jsonText = fileread(config_path);
 | 
			
		||||
    config = jsondecode(jsonText);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function write_periph_config(config)
 | 
			
		||||
    blockHandle = gcbh;
 | 
			
		||||
    mask = Simulink.Mask.get(blockHandle);
 | 
			
		||||
 | 
			
		||||
    pathparam = mask.getParameter('periphPath');
 | 
			
		||||
    config_path = pathparam.Value;
 | 
			
		||||
 | 
			
		||||
    jsonText = jsonencode(config, 'PrettyPrint', true);
 | 
			
		||||
    fid = fopen(config_path, 'w');
 | 
			
		||||
    if fid == -1
 | 
			
		||||
        error('Не удалось открыть файл periph_config.json для записи.');
 | 
			
		||||
    end
 | 
			
		||||
    fwrite(fid, jsonText, 'char');
 | 
			
		||||
    fclose(fid);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
%% CONFIG MASK TOOLS
 | 
			
		||||
function update_mask_from_config(blockPath, config)
 | 
			
		||||
    blockPath = [blockPath '/MCU'];
 | 
			
		||||
 | 
			
		||||
    % Проверяем, была ли маска открыта
 | 
			
		||||
    wasOpen = isMaskDialogOpen(blockPath);
 | 
			
		||||
    close_system(blockPath, 0);
 | 
			
		||||
    mask = Simulink.Mask.get(blockPath);
 | 
			
		||||
    
 | 
			
		||||
    tableNames = {'incTable', 'srcTable'};
 | 
			
		||||
    columns_backup = clear_tables(blockPath, tableNames);
 | 
			
		||||
 | 
			
		||||
    containerName = 'configTabAll';
 | 
			
		||||
    clear_all_from_container(mask, containerName);
 | 
			
		||||
 | 
			
		||||
    % Ищем контейнер, в который будем добавлять вкладки
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    container = find_container_by_name(allControls, containerName);
 | 
			
		||||
    if isempty(container)
 | 
			
		||||
        error('Контейнер "%s" не найден в маске.', containerName);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Проходим по каждому модулю (ADC, TIM...)
 | 
			
		||||
    periphs = fieldnames(config);
 | 
			
		||||
    for i = 1:numel(periphs)
 | 
			
		||||
        periph = periphs{i};
 | 
			
		||||
        defines = config.(periph).Defines;
 | 
			
		||||
        defNames = fieldnames(defines);
 | 
			
		||||
 | 
			
		||||
        % Создаём вкладку для модуля
 | 
			
		||||
        tabCtrl = container.addDialogControl('tab', periph);
 | 
			
		||||
        tabCtrl.Prompt = [periph ' Config'];
 | 
			
		||||
 | 
			
		||||
        for j = 1:numel(defNames)
 | 
			
		||||
            defPrompt = defNames{j};
 | 
			
		||||
            def = defines.(defPrompt);
 | 
			
		||||
            prompt = def.Prompt;
 | 
			
		||||
 | 
			
		||||
            % Только checkbox и edit
 | 
			
		||||
            switch lower(def.Type)
 | 
			
		||||
                case 'checkbox'
 | 
			
		||||
                    paramType = 'checkbox';
 | 
			
		||||
                case 'edit'
 | 
			
		||||
                    paramType = 'edit';
 | 
			
		||||
                otherwise
 | 
			
		||||
                    continue;
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            paramName = matlab.lang.makeValidName(defPrompt);
 | 
			
		||||
 | 
			
		||||
            % Преобразуем значение по типу
 | 
			
		||||
            val = def.Default;
 | 
			
		||||
            if islogical(val)
 | 
			
		||||
                if val
 | 
			
		||||
                    valStr = 'on';
 | 
			
		||||
                else
 | 
			
		||||
                    valStr = 'off';
 | 
			
		||||
                end
 | 
			
		||||
            elseif isnumeric(val)
 | 
			
		||||
                valStr = num2str(val);
 | 
			
		||||
            elseif ischar(val)
 | 
			
		||||
                valStr = val;
 | 
			
		||||
            else
 | 
			
		||||
                error('Unsupported default value type for %s.%s', periph, defPrompt);
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            % Добавляем параметр в соответствующую вкладку
 | 
			
		||||
            param = mask.addParameter( ...
 | 
			
		||||
                'Type', paramType, ...
 | 
			
		||||
                'Prompt', prompt, ...
 | 
			
		||||
                'Name', paramName, ...
 | 
			
		||||
                'Value', valStr, ...
 | 
			
		||||
                'Container', periph ...
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            param.Alias = def.Def;
 | 
			
		||||
            if def.NewRow
 | 
			
		||||
                row_param = 'new';
 | 
			
		||||
            else
 | 
			
		||||
                row_param = 'current';
 | 
			
		||||
            end
 | 
			
		||||
            param.DialogControl.Row = row_param;
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Восстанавливаем таблицы
 | 
			
		||||
    restore_tables(blockPath, tableNames, columns_backup);
 | 
			
		||||
 | 
			
		||||
    % Повторно открываем маску, если она была открыта
 | 
			
		||||
    if wasOpen
 | 
			
		||||
        open_system(blockPath, 'mask');
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function config = update_config_from_mask(blockPath, config)
 | 
			
		||||
    blockPath = [blockPath '/MCU'];
 | 
			
		||||
    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 = 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')
 | 
			
		||||
                        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 clear_all_from_container(mask, containerName)
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    container = find_container_by_name(allControls, containerName);
 | 
			
		||||
    if isempty(container)
 | 
			
		||||
        warning('Контейнер "%s" не найден.', containerName);
 | 
			
		||||
        return;
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Рекурсивно собрать все параметры (не вкладки)
 | 
			
		||||
    paramsToDelete = collect_all_parameters(container);
 | 
			
		||||
 | 
			
		||||
    % Удаляем все параметры
 | 
			
		||||
    for i = 1:numel(paramsToDelete)
 | 
			
		||||
        try
 | 
			
		||||
            mask.removeParameter(paramsToDelete{i});
 | 
			
		||||
        catch
 | 
			
		||||
            warning('Не удалось удалить параметр %s', paramsToDelete{i});
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    % Рекурсивно удалить все вкладки внутри контейнера
 | 
			
		||||
    delete_all_tabs(mask, container);
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function params = collect_all_parameters(container)
 | 
			
		||||
    params = {};
 | 
			
		||||
    children = container.DialogControls;
 | 
			
		||||
    for i = 1:numel(children)
 | 
			
		||||
        ctrl = children(i);
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab')
 | 
			
		||||
            % Если вкладка — рекурсивно собираем параметры внутри неё
 | 
			
		||||
            params = [params, collect_all_parameters(ctrl)];
 | 
			
		||||
        else
 | 
			
		||||
            % Иначе это параметр — добавляем имя
 | 
			
		||||
            params{end+1} = ctrl.Name; %#ok<AGROW>
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function delete_all_tabs(mask, container)
 | 
			
		||||
    children = container.DialogControls;
 | 
			
		||||
    % Идём в обратном порядке, чтобы безопасно удалять
 | 
			
		||||
    for i = numel(children):-1:1
 | 
			
		||||
        ctrl = children(i);
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab')
 | 
			
		||||
            % Сначала рекурсивно удаляем вкладки внутри текущей вкладки
 | 
			
		||||
            delete_all_tabs(mask, ctrl);
 | 
			
		||||
            try
 | 
			
		||||
                container.removeDialogControl(ctrl.Name);
 | 
			
		||||
            catch ME
 | 
			
		||||
                warning('Не удалось удалить вкладку %s: %s', ctrl.Name, ME.message);
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function isOpen = isMaskDialogOpen(blockPath)
 | 
			
		||||
    isOpen = false;
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
        % Получаем имя блока
 | 
			
		||||
        blockName = get_param(blockPath, 'Name');
 | 
			
		||||
 | 
			
		||||
        % Получаем список окон MATLAB GUI
 | 
			
		||||
        jWindows = java.awt.Window.getWindows();
 | 
			
		||||
 | 
			
		||||
        for i = 1:numel(jWindows)
 | 
			
		||||
            win = jWindows(i);
 | 
			
		||||
 | 
			
		||||
            % Проверка, что окно видимое и активно
 | 
			
		||||
            if win.isShowing()
 | 
			
		||||
                try
 | 
			
		||||
                    title = char(win.getTitle());
 | 
			
		||||
                    % Проверка по ключевому слову, соответствующему заголовку маски
 | 
			
		||||
                    if contains(title, ['Mask Editor: ' blockName]) || ...
 | 
			
		||||
                       contains(title, ['Mask: ' blockName]) || ...
 | 
			
		||||
                       contains(title, blockName)
 | 
			
		||||
                        isOpen = true;
 | 
			
		||||
                        return;
 | 
			
		||||
                    end
 | 
			
		||||
                catch
 | 
			
		||||
                    % Окно не имеет заголовка — пропускаем
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    catch
 | 
			
		||||
        isOpen = false;
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function column_titles = clear_tables(block, table_names)
 | 
			
		||||
    % Очищает столбцы в каждой таблице из массива имен table_names
 | 
			
		||||
    % Возвращает cell-массив с названиями первых столбцов каждой таблицы
 | 
			
		||||
    
 | 
			
		||||
    % Получить объект маски блока
 | 
			
		||||
    maskObj = Simulink.Mask.get(block);
 | 
			
		||||
    
 | 
			
		||||
    % Инициализировать cell-массив для хранения названий столбцов
 | 
			
		||||
    column_titles = cell(size(table_names));
 | 
			
		||||
    
 | 
			
		||||
    for k = 1:numel(table_names)
 | 
			
		||||
        table_name = table_names{k};
 | 
			
		||||
        
 | 
			
		||||
        % Получить объект управления таблицей
 | 
			
		||||
        tableControl = maskObj.getDialogControl(table_name);
 | 
			
		||||
        
 | 
			
		||||
        % Получить количество столбцов
 | 
			
		||||
        nCols = tableControl.getNumberOfColumns;
 | 
			
		||||
        
 | 
			
		||||
        if nCols > 0
 | 
			
		||||
            % Получить первый столбец (который будем удалять)
 | 
			
		||||
            column = tableControl.getColumn(1);
 | 
			
		||||
            column_titles{k} = column.Name;
 | 
			
		||||
            
 | 
			
		||||
            % Удаляем все столбцы
 | 
			
		||||
            % Важно: при удалении столбцов индексы меняются, 
 | 
			
		||||
            % поэтому удаляем всегда первый столбец nCols раз
 | 
			
		||||
            for i = 1:nCols
 | 
			
		||||
                tableControl.removeColumn(1);
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
            % Если столбцов нет, возвращаем пустую строку
 | 
			
		||||
            column_titles{k} = '';
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function restore_tables(block, table_names, column_titles)
 | 
			
		||||
    % Восстанавливает первый столбец в каждой таблице из массива имен
 | 
			
		||||
    % Использует массив column_titles для установки имени столбца
 | 
			
		||||
    
 | 
			
		||||
    % Получить объект маски блока
 | 
			
		||||
    maskObj = Simulink.Mask.get(block);
 | 
			
		||||
    
 | 
			
		||||
    for k = 1:numel(table_names)
 | 
			
		||||
        table_name = table_names{k};
 | 
			
		||||
        title = column_titles{k};
 | 
			
		||||
        
 | 
			
		||||
        % Получить объект управления таблицей
 | 
			
		||||
        tableControl = maskObj.getDialogControl(table_name);
 | 
			
		||||
        
 | 
			
		||||
        % Добавить новый столбец
 | 
			
		||||
        column = tableControl.addColumn(Name='title', Type='edit');
 | 
			
		||||
        column.Name = title;
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function tab = find_tab_by_name(controls, targetName)
 | 
			
		||||
    tab = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, вкладка ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            tab = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это контейнер — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            tab = find_tab_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(tab)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function container = find_container_by_name(controls, targetName)
 | 
			
		||||
    container = [];
 | 
			
		||||
 | 
			
		||||
    for i = 1:numel(controls)
 | 
			
		||||
        ctrl = controls(i);
 | 
			
		||||
 | 
			
		||||
        % Проверяем, контейнер ли это и совпадает ли имя
 | 
			
		||||
        if isa(ctrl, 'Simulink.dialog.Container') && strcmp(ctrl.Name, targetName)
 | 
			
		||||
            container = ctrl;
 | 
			
		||||
            return;
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        % Если это вложенный контрол — обходим его детей
 | 
			
		||||
        children = get_children(ctrl);
 | 
			
		||||
        if ~isempty(children)
 | 
			
		||||
            container = find_container_by_name(children, targetName);
 | 
			
		||||
            if ~isempty(container)
 | 
			
		||||
                return;
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function children = get_children(ctrl)
 | 
			
		||||
    if isprop(ctrl, 'DialogControls')
 | 
			
		||||
        children = ctrl.DialogControls;
 | 
			
		||||
    elseif isprop(ctrl, 'Controls')
 | 
			
		||||
        children = ctrl.Controls;
 | 
			
		||||
    elseif isprop(ctrl, 'Children')
 | 
			
		||||
        children = ctrl.Children;
 | 
			
		||||
    else
 | 
			
		||||
        children = [];
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -1,38 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "ADC": {
 | 
			
		||||
    "Defines": {
 | 
			
		||||
      "ADC1 Enable": {
 | 
			
		||||
        "Def": "ADC1_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true
 | 
			
		||||
      },
 | 
			
		||||
      "ADC2 Enable": {
 | 
			
		||||
        "Def": "ADC2_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true
 | 
			
		||||
      },
 | 
			
		||||
      "SAMPLE_RATE": {
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 48000
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "TIM": {
 | 
			
		||||
    "Defines": {
 | 
			
		||||
      "TIM1 Enable": {
 | 
			
		||||
        "Def": "ADC1_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM2 Enable": {
 | 
			
		||||
        "Def": "ADC2_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true
 | 
			
		||||
      },
 | 
			
		||||
      "AHB Buf Clock Rate": {
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 72
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,40 +1,252 @@
 | 
			
		||||
{
 | 
			
		||||
  "ADC": {
 | 
			
		||||
  "RCC": {
 | 
			
		||||
    "Defines": {
 | 
			
		||||
      "ADC1 Enable": {
 | 
			
		||||
        "Def": "ADC1_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true
 | 
			
		||||
      },
 | 
			
		||||
      "ADC2 Enable": {
 | 
			
		||||
        "Def": "ADC2_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true
 | 
			
		||||
      },
 | 
			
		||||
      "Sample Rate (Hz)": {
 | 
			
		||||
        "Def": "SAMPLE_RATE",
 | 
			
		||||
      "HCLK_Clock": {
 | 
			
		||||
        "Prompt": "HCLK Clock (Hz)",
 | 
			
		||||
        "Def": "HCLK_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 48000
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ABP1_Clock": {
 | 
			
		||||
        "Prompt": "ABP1 Clock (Hz)",
 | 
			
		||||
        "Def": "ABP1_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ABP1_TIMS_Clock": {
 | 
			
		||||
        "Prompt": "ABP1 Tim's Clock (Hz)",
 | 
			
		||||
        "Def": "ABP1_TIMS_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ABP2_Clock": {
 | 
			
		||||
        "Prompt": "ABP2 Clock (Hz)",
 | 
			
		||||
        "Def": "ABP2_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ABP2_TIMS_Clock": {
 | 
			
		||||
        "Prompt": "ABP2 Tim's Clock (Hz)",
 | 
			
		||||
        "Def": "ABP2_TIMS_Value",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 7.2E+7,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "TIM": {
 | 
			
		||||
    "Defines": {
 | 
			
		||||
      "TIM1 Enable": {
 | 
			
		||||
        "Def": "TIM1_ENABLE",
 | 
			
		||||
      "TIM1_Enable": {
 | 
			
		||||
        "Prompt": "TIM1 Enable",
 | 
			
		||||
        "Def": "USE_TIM1",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM2 Enable": {
 | 
			
		||||
        "Def": "TIM2_ENABLE",
 | 
			
		||||
      "TIM1_UP_TIM10_Handler": {
 | 
			
		||||
        "Prompt": "TIM1_UP_TIM10 Handler",
 | 
			
		||||
        "Def": "USE_TIM1_UP_TIM10_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "AHB Buf Clock Rate (MHz)": {
 | 
			
		||||
        "Def": "AHB_BUS_FREQ",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 72
 | 
			
		||||
      "TIM2_Enable": {
 | 
			
		||||
        "Prompt": "TIM2 Enable",
 | 
			
		||||
        "Def": "USE_TIM2",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM2_Handler": {
 | 
			
		||||
        "Prompt": "TIM2 Handler",
 | 
			
		||||
        "Def": "USE_TIM2_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM3_Enable": {
 | 
			
		||||
        "Prompt": "TIM3 Enable",
 | 
			
		||||
        "Def": "USE_TIM3",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM3_Handler": {
 | 
			
		||||
        "Prompt": "TIM3 Handler",
 | 
			
		||||
        "Def": "USE_TIM3_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM4_Enable": {
 | 
			
		||||
        "Prompt": "TIM4 Enable",
 | 
			
		||||
        "Def": "USE_TIM4",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM4_Handler": {
 | 
			
		||||
        "Prompt": "TIM4 Handler",
 | 
			
		||||
        "Def": "USE_TIM4_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM5_Enable": {
 | 
			
		||||
        "Prompt": "TIM5 Enable",
 | 
			
		||||
        "Def": "USE_TIM5",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM5_Handler": {
 | 
			
		||||
        "Prompt": "TIM5 Handler",
 | 
			
		||||
        "Def": "USE_TIM5_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM6_Enable": {
 | 
			
		||||
        "Prompt": "TIM6 Enable",
 | 
			
		||||
        "Def": "USE_TIM6",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM6_Handler": {
 | 
			
		||||
        "Prompt": "TIM6 Handler",
 | 
			
		||||
        "Def": "USE_TIM6_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM7_Enable": {
 | 
			
		||||
        "Prompt": "TIM7 Enable",
 | 
			
		||||
        "Def": "USE_TIM7",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM7_Handler": {
 | 
			
		||||
        "Prompt": "TIM7 Handler",
 | 
			
		||||
        "Def": "USE_TIM7_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM8_Enable": {
 | 
			
		||||
        "Prompt": "TIM8 Enable",
 | 
			
		||||
        "Def": "USE_TIM8",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM8_UP_TIM13_Handler": {
 | 
			
		||||
        "Prompt": "TIM8_UP_TIM13 Handler",
 | 
			
		||||
        "Def": "USE_TIM8_UP_TIM13_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM9_Enable": {
 | 
			
		||||
        "Prompt": "TIM9 Enable",
 | 
			
		||||
        "Def": "USE_TIM9",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM1_BRK_TIM9_Handler": {
 | 
			
		||||
        "Prompt": "TIM1_BRK_TIM9 Handler",
 | 
			
		||||
        "Def": "USE_TIM1_BRK_TIM9_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM10_Enable": {
 | 
			
		||||
        "Prompt": "TIM10 Enable",
 | 
			
		||||
        "Def": "USE_TIM10",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM11_Enable": {
 | 
			
		||||
        "Prompt": "TIM11 Enable",
 | 
			
		||||
        "Def": "USE_TIM11",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM1_TRG_COM_TIM11_Handler": {
 | 
			
		||||
        "Prompt": "TIM1_TRG_COM_TIM11 Handler",
 | 
			
		||||
        "Def": "USE_TIM1_TRG_COM_TIM11_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM12_Enable": {
 | 
			
		||||
        "Prompt": "TIM12 Enable",
 | 
			
		||||
        "Def": "USE_TIM12",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM8_BRK_TIM12_Handler": {
 | 
			
		||||
        "Prompt": "TIM8_BRK_TIM12 Handler",
 | 
			
		||||
        "Def": "USE_TIM8_BRK_TIM12_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      },
 | 
			
		||||
      "TIM13_Enable": {
 | 
			
		||||
        "Prompt": "TIM13 Enable",
 | 
			
		||||
        "Def": "USE_TIM13",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM14_Enable": {
 | 
			
		||||
        "Prompt": "TIM14 Enable",
 | 
			
		||||
        "Def": "USE_TIM14",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "TIM8_TRG_COM_TIM14_Handler": {
 | 
			
		||||
        "Prompt": "TIM8_TRG_COM_TIM14 Handler",
 | 
			
		||||
        "Def": "USE_TIM8_TRG_COM_TIM14_HANDLER",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": false,
 | 
			
		||||
        "NewRow": false
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  "ADC": {
 | 
			
		||||
    "Defines": {
 | 
			
		||||
      "ADC1_Enable": {
 | 
			
		||||
        "Prompt": "ADC1 Enable",
 | 
			
		||||
        "Def": "ADC1_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "ADC2_Enable": {
 | 
			
		||||
        "Prompt": "ADC2 Enable",
 | 
			
		||||
        "Def": "ADC2_ENABLE",
 | 
			
		||||
        "Type": "checkbox",
 | 
			
		||||
        "Default": true,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      },
 | 
			
		||||
      "Sample_Rate": {
 | 
			
		||||
        "Prompt": "Sample Rate (Hz)",
 | 
			
		||||
        "Def": "SAMPLE_RATE",
 | 
			
		||||
        "Type": "edit",
 | 
			
		||||
        "Default": 48000,
 | 
			
		||||
        "NewRow": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user