Compare commits
	
		
			2 Commits
		
	
	
		
			5e93fc2099
			...
			e7e0884c09
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e7e0884c09 | |||
| 0f3ac734bf | 
@ -28,9 +28,12 @@ extern "C" {
 | 
			
		||||
 | 
			
		||||
/* Includes ------------------------------------------------------------------*/
 | 
			
		||||
#include "stm32f1xx.h"
 | 
			
		||||
#include "stm32_defs.h"
 | 
			
		||||
#include "Legacy/stm32_hal_legacy.h"
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
#include "stm32f1xx_matlab_rcc.h"
 | 
			
		||||
#include "stm32f1xx_matlab_gpio.h"
 | 
			
		||||
#include "stm32f1xx_matlab_tim.h"
 | 
			
		||||
 | 
			
		||||
/* Exported types ------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,8 @@
 | 
			
		||||
#define _MATLAB_GPIO_H_
 | 
			
		||||
 | 
			
		||||
#include "simstruc.h"
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
#include "stm32f1xx_matlab_conf.h"
 | 
			
		||||
//#include "mcu_wrapper_conf.h"
 | 
			
		||||
 | 
			
		||||
/* äåôàéíû äëÿ ïðîâåðêè êîíôèãóðàöèè GPIO) */
 | 
			
		||||
#define GET_GPIO_CONF(_reg_, _pos_)         ((_pos_ < 8)?                                                                                                   \
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#ifndef _MATLAB_RCC_H_
 | 
			
		||||
#define _MATLAB_RCC_H_
 | 
			
		||||
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
#include "stm32f1xx_matlab_conf.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,8 @@
 | 
			
		||||
#define _MATLAB_TIM_H_
 | 
			
		||||
 | 
			
		||||
#include "stm32f1xx_it.h"
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
#include "stm32f1xx_matlab_conf.h"
 | 
			
		||||
//#include "mcu_wrapper_conf.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
äåôàéíàìè â stm32f4xx_matlab_conf.h.
 | 
			
		||||
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
#include "stm32f1xx_matlab_conf.h"
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
 | 
			
		||||
MCU_MemoryTypeDef MCU_MEM;
 | 
			
		||||
@ -85,7 +86,7 @@ void Init_TIM_SIM(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef USE_TIM1    
 | 
			
		||||
	tim1s.tx_cnt = TIM1->CNT;
 | 
			
		||||
	tim1s.tx_step = hmcu.SIM_Sample_Time * ABP2_TIMS_Value;
 | 
			
		||||
	tim1s.tx_step = hmcu.sSimSampleTime * ABP2_TIMS_Value;
 | 
			
		||||
 | 
			
		||||
	tim1s.Channels.OC1_GPIOx = GPIOA;
 | 
			
		||||
	tim1s.Channels.OC1_PIN_SHIFT = 8;
 | 
			
		||||
@ -98,7 +99,7 @@ void Init_TIM_SIM(void)
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_TIM2
 | 
			
		||||
	tim2s.tx_cnt = TIM2->CNT;
 | 
			
		||||
	tim2s.tx_step = hmcu.SIM_Sample_Time * ABP1_TIMS_Value;
 | 
			
		||||
	tim2s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
 | 
			
		||||
 | 
			
		||||
	tim2s.Channels.OC1_GPIOx = GPIOA;
 | 
			
		||||
	tim2s.Channels.OC1_PIN_SHIFT = 5;
 | 
			
		||||
@ -111,7 +112,7 @@ void Init_TIM_SIM(void)
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_TIM3
 | 
			
		||||
	tim3s.tx_cnt = TIM3->CNT;
 | 
			
		||||
	tim3s.tx_step = hmcu.SIM_Sample_Time * ABP1_TIMS_Value;
 | 
			
		||||
	tim3s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
 | 
			
		||||
 | 
			
		||||
	tim3s.Channels.OC1_GPIOx = GPIOB;
 | 
			
		||||
	tim3s.Channels.OC1_PIN_SHIFT = 4;
 | 
			
		||||
@ -124,7 +125,7 @@ void Init_TIM_SIM(void)
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_TIM4	
 | 
			
		||||
	tim4s.tx_cnt = TIM4->CNT;
 | 
			
		||||
	tim4s.tx_step = hmcu.SIM_Sample_Time * ABP1_TIMS_Value;
 | 
			
		||||
	tim4s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
 | 
			
		||||
 | 
			
		||||
	tim4s.Channels.OC1_GPIOx = GPIOD;
 | 
			
		||||
	tim4s.Channels.OC1_PIN_SHIFT = 12;
 | 
			
		||||
@ -137,7 +138,7 @@ void Init_TIM_SIM(void)
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_TIM5
 | 
			
		||||
	tim5s.tx_cnt = TIM5->CNT;
 | 
			
		||||
	tim5s.tx_step = hmcu.SIM_Sample_Time * ABP1_TIMS_Value;
 | 
			
		||||
	tim5s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
 | 
			
		||||
 | 
			
		||||
	tim5s.Channels.OC1_GPIOx = GPIOA;
 | 
			
		||||
	tim5s.Channels.OC1_PIN_SHIFT = 0;
 | 
			
		||||
@ -150,7 +151,7 @@ void Init_TIM_SIM(void)
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_TIMx
 | 
			
		||||
	tim6s.tx_cnt = TIMx->CNT;
 | 
			
		||||
	tim6s.tx_step = hmcu.SIM_Sample_Time * ABP1_TIMS_Value;
 | 
			
		||||
	tim6s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
 | 
			
		||||
 | 
			
		||||
	tim6s.Channels.OC1_GPIOx = GPIOA;
 | 
			
		||||
	tim6s.Channels.OC1_PIN_SHIFT = 0;
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,6 @@
 | 
			
		||||
#define _MATLAB_SETUP_H_
 | 
			
		||||
#include "stm32_defs.h"
 | 
			
		||||
#include "stm32f1xx_hal.h"
 | 
			
		||||
//#include "mcu_wrapper_conf.h"
 | 
			
		||||
 | 
			
		||||
// DEFINES (UNCOMMENT WHAT YOU WILL SIMULATE)
 | 
			
		||||
// TIMS
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,57 @@
 | 
			
		||||
{
 | 
			
		||||
  "Code": {
 | 
			
		||||
    "Sources": {
 | 
			
		||||
      "Type": "files",
 | 
			
		||||
      "Options": [
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_adc.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_adc_ex.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c",
 | 
			
		||||
        "stm32f1xx_matlab_conf.c",
 | 
			
		||||
        "Drivers/STM32F1xx_SIMULINK/stm32f1xx_matlab_gpio.c",
 | 
			
		||||
        "Drivers/STM32F1xx_SIMULINK/stm32f1xx_matlab_tim.c",
 | 
			
		||||
        "Drivers/STM32F1xx_SIMULINK/stm32f1xx_periph_registers.c"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    "Includes": {
 | 
			
		||||
      "Type": "paths",
 | 
			
		||||
      "Options": [
 | 
			
		||||
        "",
 | 
			
		||||
        "Drivers/STM32F1xx_SIMULINK",
 | 
			
		||||
        "Drivers/CMSIS",
 | 
			
		||||
        "Drivers/CMSIS/Device/STM32F1xx",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Inc",
 | 
			
		||||
        "Drivers/STM32F1xx_HAL_Driver/Inc/Legacy"
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "UserCode": {
 | 
			
		||||
    "Functions": {
 | 
			
		||||
      "PeriphInit": {
 | 
			
		||||
        "Options": [
 | 
			
		||||
          "Initialize_Periph_Sim()"
 | 
			
		||||
        ]
 | 
			
		||||
      },
 | 
			
		||||
      "PeriphSimulation": {
 | 
			
		||||
        "Options": [
 | 
			
		||||
          "Simulate_TIMs()",
 | 
			
		||||
          "Simulate_GPIO_BSRR()"
 | 
			
		||||
        ]
 | 
			
		||||
      },
 | 
			
		||||
      "PeriphDeinit": {
 | 
			
		||||
        "Options": [
 | 
			
		||||
          "deInitialize_Periph_Sim()"
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "RCC": {
 | 
			
		||||
    "Defines": {
 | 
			
		||||
      "HCLK_Clock": {
 | 
			
		||||
@ -19,7 +19,7 @@
 | 
			
		||||
  * @{
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
#define S_FUNCTION_NAME     MCU
 | 
			
		||||
#define S_FUNCTION_NAME MCU
 | 
			
		||||
#define S_FUNCTION_LEVEL    2
 | 
			
		||||
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
@ -111,16 +111,18 @@ static void mdlInitializeSizes(SimStruct* S)
 | 
			
		||||
	ssSetNumDiscStates(S, DISC_STATES_WIDTH);	// number of discrete states
 | 
			
		||||
 | 
			
		||||
	// set up input port
 | 
			
		||||
	if (!ssSetNumInputPorts(S, 1)) return;
 | 
			
		||||
	if (!ssSetNumInputPorts(S, IN_PORT_NUMB)) return;
 | 
			
		||||
	for (int i = 0; i < IN_PORT_NUMB; i++)
 | 
			
		||||
		ssSetInputPortWidth(S, i, IN_PORT_WIDTH);
 | 
			
		||||
	ssSetInputPortDirectFeedThrough(S, 0, 0);
 | 
			
		||||
	ssSetInputPortRequiredContiguous(S, 0, 1); // direct input signal access
 | 
			
		||||
	{
 | 
			
		||||
		ssSetInputPortWidth(S, i, inLengths[i]);
 | 
			
		||||
		ssSetInputPortDirectFeedThrough(S, i, 0);
 | 
			
		||||
		ssSetInputPortRequiredContiguous(S, i, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// set up output port
 | 
			
		||||
	if (!ssSetNumOutputPorts(S, OUT_PORT_NUMB)) return;
 | 
			
		||||
	for (int i = 0; i < OUT_PORT_NUMB; i++)
 | 
			
		||||
		ssSetOutputPortWidth(S, i, OUT_PORT_WIDTH);
 | 
			
		||||
		ssSetOutputPortWidth(S, i, outLengths[i]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	ssSetNumSampleTimes(S, 1);
 | 
			
		||||
@ -152,7 +154,7 @@ static void mdlInitializeSizes(SimStruct* S)
 | 
			
		||||
 */
 | 
			
		||||
static void mdlStart(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
	SIM_Initialize_Simulation();
 | 
			
		||||
	SIM_Initialize_Simulation(S);
 | 
			
		||||
}
 | 
			
		||||
#endif // MDL_START
 | 
			
		||||
 | 
			
		||||
@ -167,10 +169,10 @@ static void mdlStart(SimStruct* S)
 | 
			
		||||
static void mdlInitializeSampleTimes(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
	// Шаг дискретизации
 | 
			
		||||
	hmcu.SIM_Sample_Time = mxGetPr(ssGetSFcnParam(S, NPARAMS - 1))[0];
 | 
			
		||||
	hmcu.sSimSampleTime = mxGetPr(ssGetSFcnParam(S, NPARAMS - 1))[0];
 | 
			
		||||
 | 
			
		||||
	// Register one pair for each sample time
 | 
			
		||||
	ssSetSampleTime(S, 0, hmcu.SIM_Sample_Time);
 | 
			
		||||
	ssSetSampleTime(S, 0, hmcu.sSimSampleTime);
 | 
			
		||||
	ssSetOffsetTime(S, 0, 0.0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -189,7 +191,7 @@ static void mdlTerminate(SimStruct* S)
 | 
			
		||||
	ResumeThread(hmcu.hMCUThread);
 | 
			
		||||
	WaitForSingleObject(hmcu.hMCUThread, 10000);
 | 
			
		||||
#endif
 | 
			
		||||
	SIM_deInitialize_Simulation();
 | 
			
		||||
	SIM_deInitialize_Simulation(S);
 | 
			
		||||
	mexUnlock();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,138 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
**************************************************************************
 | 
			
		||||
* @file app_wrapper.c
 | 
			
		||||
* @brief Код для из приложения МК для симуляции.
 | 
			
		||||
**************************************************************************
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
// Includes START
 | 
			
		||||
#include "upp.h"
 | 
			
		||||
#include "main.h"
 | 
			
		||||
// Inlcudes END
 | 
			
		||||
 | 
			
		||||
// Dummy functions START
 | 
			
		||||
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk) {}
 | 
			
		||||
void SystemClock_Config(void) {}
 | 
			
		||||
void Error_Handler(void) {}
 | 
			
		||||
// Dummy functions END
 | 
			
		||||
 | 
			
		||||
void app_init(void)
 | 
			
		||||
{
 | 
			
		||||
/* USER CODE BEGIN 1 */
 | 
			
		||||
 | 
			
		||||
    /* USER CODE END 1 */
 | 
			
		||||
 | 
			
		||||
    /* MCU Configuration--------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 | 
			
		||||
    HAL_Init();
 | 
			
		||||
 | 
			
		||||
    /* USER CODE BEGIN Init */
 | 
			
		||||
 | 
			
		||||
    /* USER CODE END Init */
 | 
			
		||||
 | 
			
		||||
    /* Configure the system clock */
 | 
			
		||||
    SystemClock_Config();
 | 
			
		||||
 | 
			
		||||
    /* USER CODE BEGIN SysInit */
 | 
			
		||||
 | 
			
		||||
    /* USER CODE END SysInit */
 | 
			
		||||
 | 
			
		||||
    /* Initialize all configured peripherals */
 | 
			
		||||
    MX_GPIO_Init();
 | 
			
		||||
    MX_TIM2_Init();
 | 
			
		||||
    /* USER CODE BEGIN 2 */
 | 
			
		||||
    upp_init();
 | 
			
		||||
 | 
			
		||||
    /* USER CODE END 2 */
 | 
			
		||||
 | 
			
		||||
    /* Infinite loop */
 | 
			
		||||
    /* USER CODE BEGIN WHILE */
 | 
			
		||||
    //while (1)
 | 
			
		||||
    //{
 | 
			
		||||
    //    upp_main();
 | 
			
		||||
    //    /* USER CODE END WHILE */
 | 
			
		||||
 | 
			
		||||
    //    /* USER CODE BEGIN 3 */
 | 
			
		||||
    //}
 | 
			
		||||
    /* USER CODE END 3 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void app_step(void)
 | 
			
		||||
{
 | 
			
		||||
    upp_main();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void app_writeOutputBuffer(real_T* disc)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < PORT_WIDTH; i++)
 | 
			
		||||
    {
 | 
			
		||||
        if (GPIOA->ODR & (1 << i))
 | 
			
		||||
        {
 | 
			
		||||
            disc[i] = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (GPIOB->ODR & (1 << i))
 | 
			
		||||
        {
 | 
			
		||||
            disc[PORT_WIDTH + i] = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    disc[2 * PORT_WIDTH + 0] = phase_A.ctrl.angle.delay_us;
 | 
			
		||||
    disc[2 * PORT_WIDTH + 1] = (uint16_t)((uint16_t)TIMER->CNT - phase_A.ctrl.angle.start_delay_tick);
 | 
			
		||||
    disc[2 * PORT_WIDTH + 2] = phase_A.ctrl.angle.start_delay_tick;
 | 
			
		||||
    disc[2 * PORT_WIDTH + 3] = TIMER->CNT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void app_readInputs(real_T* in)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#define detect_front(_in_numb_, _var_, _val_) {             \
 | 
			
		||||
if ((in[_in_numb_] > 0.5) && (prev_in[_in_numb_] <= 0.5))   \
 | 
			
		||||
{                                                           \
 | 
			
		||||
    _var_ = _val_;                                          \
 | 
			
		||||
} }
 | 
			
		||||
 | 
			
		||||
#define detect_rise(_in_numb_, _var_, _val_) {              \
 | 
			
		||||
if ((in[_in_numb_] < 0.5) && (prev_in[_in_numb_] >= 0.5))   \
 | 
			
		||||
{                                                           \
 | 
			
		||||
    _var_ = _val_;                                          \
 | 
			
		||||
} }
 | 
			
		||||
 | 
			
		||||
    static real_T prev_in[IN_PORT_WIDTH];
 | 
			
		||||
 | 
			
		||||
    detect_front(0, phase_A.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
    detect_rise(0, phase_A.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
 | 
			
		||||
    detect_front(1, phase_B.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
    detect_rise(1, phase_B.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
 | 
			
		||||
    detect_front(2, phase_C.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
    detect_rise(2, phase_C.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
 | 
			
		||||
    detect_front(3, Upp.GoSafe, 1);
 | 
			
		||||
    detect_rise(3, Upp.GoSafe, 0);
 | 
			
		||||
 | 
			
		||||
    detect_front(4, Upp.Prepare, 1);
 | 
			
		||||
    detect_rise(4, Upp.Prepare, 0);
 | 
			
		||||
 | 
			
		||||
    detect_front(5, Upp.ForceStop, 1);
 | 
			
		||||
    detect_rise(5, Upp.ForceStop, 0);
 | 
			
		||||
 | 
			
		||||
    detect_front(6, Upp.ForceDisconnect, 1);
 | 
			
		||||
    detect_rise(6, Upp.ForceDisconnect, 0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Upp.sine_freq = in[7];
 | 
			
		||||
    Upp.Duration = in[8];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < IN_PORT_WIDTH; i++)
 | 
			
		||||
    {
 | 
			
		||||
        prev_in[i] = in[i];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@ -7,6 +7,7 @@
 | 
			
		||||
Данный файл содержит функции для симуляции МК в Simulink (S-Function).
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
#include "app_wrapper.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
    * @addtogroup	WRAPPER_CONF
 | 
			
		||||
@ -15,6 +16,41 @@
 | 
			
		||||
 | 
			
		||||
SIM__MCUHandleTypeDef hmcu;         ///< Хендл для управления потоком программы МК
 | 
			
		||||
 | 
			
		||||
// INPUT/OUTPUTS AUTO-PARAMS START
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Таблица длин массивов IN
 | 
			
		||||
  */
 | 
			
		||||
const int inLengths[IN_PORT_NUMB] = {
 | 
			
		||||
    IN_PORT_1_WIDTH,
 | 
			
		||||
    IN_PORT_2_WIDTH
 | 
			
		||||
};
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Таблица смещений в выходном массиве IN
 | 
			
		||||
  */
 | 
			
		||||
const int inOffsets[IN_PORT_NUMB] = {
 | 
			
		||||
    OFFSET_IN_ARRAY_1,
 | 
			
		||||
    OFFSET_IN_ARRAY_2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Таблица длин массивов OUT
 | 
			
		||||
  */
 | 
			
		||||
const int outLengths[OUT_PORT_NUMB] = {
 | 
			
		||||
    OUT_PORT_1_WIDTH,
 | 
			
		||||
    OUT_PORT_2_WIDTH,
 | 
			
		||||
    OUT_PORT_3_WIDTH
 | 
			
		||||
};
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Таблица смещений в выходном массиве OUT
 | 
			
		||||
  */
 | 
			
		||||
const int outOffsets[OUT_PORT_NUMB] = {
 | 
			
		||||
    OFFSET_OUT_ARRAY_1,
 | 
			
		||||
    OFFSET_OUT_ARRAY_2,
 | 
			
		||||
    OFFSET_OUT_ARRAY_3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// INPUT/OUTPUTS AUTO-PARAMS END
 | 
			
		||||
 | 
			
		||||
/** MCU_WRAPPER
 | 
			
		||||
    * @}
 | 
			
		||||
    */
 | 
			
		||||
@ -50,13 +86,13 @@ unsigned __stdcall MCU_App_Thread(void) {
 | 
			
		||||
  */
 | 
			
		||||
void MCU_Step_Simulation(SimStruct* S, time_T time)
 | 
			
		||||
{
 | 
			
		||||
    hmcu.SystemClockDouble += hmcu.SystemClock_step; // emulate core clock 
 | 
			
		||||
    hmcu.SystemClockDouble += hmcu.sSystemClock_step; // emulate core clock 
 | 
			
		||||
    hmcu.SystemClock = hmcu.SystemClockDouble;
 | 
			
		||||
    hmcu.SimTime = time;
 | 
			
		||||
 | 
			
		||||
    MCU_readInputs(S); // считывание портов
 | 
			
		||||
 | 
			
		||||
    MCU_Periph_Simulation(); // simulate peripheral
 | 
			
		||||
    MCU_Periph_Simulation(S); // simulate peripheral
 | 
			
		||||
 | 
			
		||||
#ifdef RUN_APP_MAIN_FUNC_THREAD
 | 
			
		||||
    ResumeThread(hmcu.hMCUThread);
 | 
			
		||||
@ -76,25 +112,26 @@ void MCU_Step_Simulation(SimStruct* S, time_T time)
 | 
			
		||||
  * @brief      Симуляция периферии МК
 | 
			
		||||
  * @details    Пользовательский код, который симулирует работу периферии МК.
 | 
			
		||||
  */
 | 
			
		||||
void MCU_Periph_Simulation(void)
 | 
			
		||||
void MCU_Periph_Simulation(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
    uwTick = hmcu.SystemClock / (MCU_CORE_CLOCK / 1000);
 | 
			
		||||
 | 
			
		||||
    Simulate_TIMs();   
 | 
			
		||||
// PERIPH SIM START
 | 
			
		||||
	Simulate_TIMs();
 | 
			
		||||
	Simulate_GPIO_BSRR();
 | 
			
		||||
// PERIPH SIM END
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* READ INPUTS S-FUNCTION TO MCU REGS */
 | 
			
		||||
/**
 | 
			
		||||
  * @brief      Считывание входов S-Function в порты ввода-вывода.
 | 
			
		||||
 *	@param		S - указатель на структуру S-Function из "simstruc.h"
 | 
			
		||||
  * @details    Пользовательский код, который записывает порты ввода-вывода из входов S-Function.
 | 
			
		||||
  * @details    Пользовательский код, который записывает входы МК из входов S-Function.
 | 
			
		||||
  */
 | 
			
		||||
void MCU_readInputs(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
    /* Get S-Function inputs */
 | 
			
		||||
    real_T* IN = ssGetInputPortRealSignal(S, 0);
 | 
			
		||||
 | 
			
		||||
    app_readInputs(IN);
 | 
			
		||||
    SIM_readInputs(S);
 | 
			
		||||
    /* Get S-Function descrete array (IO buffer) */
 | 
			
		||||
    real_T* In_Buff = ssGetDiscStates(S);
 | 
			
		||||
    app_readInputs(In_Buff);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* WRITE OUTPUTS BUFFER S-FUNCTION FROM MCU REGS*/
 | 
			
		||||
@ -105,10 +142,9 @@ void MCU_readInputs(SimStruct* S)
 | 
			
		||||
  */
 | 
			
		||||
void MCU_writeOutputs(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
    /* Get S-Function descrete array */
 | 
			
		||||
    /* Get S-Function descrete array (IO buffer) */
 | 
			
		||||
    real_T* Out_Buff = ssGetDiscStates(S);
 | 
			
		||||
 | 
			
		||||
    Simulate_GPIO_BSRR();
 | 
			
		||||
    app_writeOutputBuffer(Out_Buff);
 | 
			
		||||
}
 | 
			
		||||
//-----------------CONTROLLER SIMULATE FUNCTIONS---------------//
 | 
			
		||||
@ -118,65 +154,129 @@ void MCU_writeOutputs(SimStruct* S)
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------//
 | 
			
		||||
//----------------------SIMULINK FUNCTIONS---------------------//
 | 
			
		||||
/* WRITE OUTPUTS OF S-BLOCK */
 | 
			
		||||
/**
 | 
			
		||||
  * @brief      Формирование выходов S-Function.
 | 
			
		||||
 *	@param		S - указатель на структуру S-Function из "simstruc.h"
 | 
			
		||||
  * @details    Пользовательский код, который записывает выходы S-Function из буфера.
 | 
			
		||||
  */
 | 
			
		||||
void SIM_writeOutputs(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
    real_T* GPIO;
 | 
			
		||||
    real_T* Out_Buff = ssGetDiscStates(S);
 | 
			
		||||
 | 
			
		||||
    //-------------WRITTING GPIOS---------------
 | 
			
		||||
    for (int j = 0; j < PORT_NUMB; j++)
 | 
			
		||||
    {
 | 
			
		||||
        GPIO = ssGetOutputPortRealSignal(S, j);
 | 
			
		||||
        for (int i = 0; i < PORT_WIDTH; i++)
 | 
			
		||||
        {
 | 
			
		||||
            GPIO[i] = Out_Buff[j * PORT_WIDTH + i];
 | 
			
		||||
            Out_Buff[j * PORT_WIDTH + i] = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    //------------------------------------------
 | 
			
		||||
}
 | 
			
		||||
/* MCU WRAPPER DEINITIALIZATION */
 | 
			
		||||
/**
 | 
			
		||||
  * @brief      Инициализация симуляции МК.
 | 
			
		||||
  * @details    Пользовательский код, который создает поток для приложения МК
 | 
			
		||||
  * @details    Пользовательский код, который создает поток для приложения МК 
 | 
			
		||||
                и настраивает симулятор МК для симуляции.
 | 
			
		||||
  */
 | 
			
		||||
void SIM_Initialize_Simulation(void)
 | 
			
		||||
void SIM_Initialize_Simulation(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
#ifdef RUN_APP_MAIN_FUNC_THREAD
 | 
			
		||||
    // инициализация потока, который будет выполнять код МК
 | 
			
		||||
    hmcu.hMCUThread = (HANDLE)CreateThread(NULL, 0, MCU_App_Thread, 0, CREATE_SUSPENDED, &hmcu.idMCUThread);
 | 
			
		||||
#else
 | 
			
		||||
    extern int app_init(void);
 | 
			
		||||
    app_init();
 | 
			
		||||
#endif //RUN_APP_MAIN_FUNC_THREAD
 | 
			
		||||
 | 
			
		||||
    /* user initialization */
 | 
			
		||||
    Initialize_Periph_Sim();
 | 
			
		||||
 | 
			
		||||
    /* wrapper initialization */
 | 
			
		||||
    hmcu.SystemClock_step = MCU_CORE_CLOCK * hmcu.SIM_Sample_Time;   // set system clock step
 | 
			
		||||
    app_init();
 | 
			
		||||
// PERIPH INIT START
 | 
			
		||||
	Initialize_Periph_Sim();
 | 
			
		||||
// PERIPH INIT END
 | 
			
		||||
    
 | 
			
		||||
    /* clock step initialization */
 | 
			
		||||
    hmcu.sSystemClock_step = MCU_CORE_CLOCK * hmcu.sSimSampleTime;   // set system clock step
 | 
			
		||||
    hmcu.fInitDone = 1;
 | 
			
		||||
}
 | 
			
		||||
/* MCU WRAPPER DEINITIALIZATION */
 | 
			
		||||
/**
 | 
			
		||||
  * @brief      Деинициализация симуляции МК.
 | 
			
		||||
  * @details    Пользовательский код, который будет очищать все структуры после окончания симуляции.
 | 
			
		||||
  */
 | 
			
		||||
void SIM_deInitialize_Simulation(void)
 | 
			
		||||
void SIM_deInitialize_Simulation(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
//#ifdef DEINITIALIZE_AFTER_SIM
 | 
			
		||||
#include "upp.h"
 | 
			
		||||
    memset(&Upp, 0, sizeof(Upp));
 | 
			
		||||
    // simulate structures of peripheral deinitialization
 | 
			
		||||
    deInitialize_Periph_Sim();
 | 
			
		||||
    // mcu peripheral memory deinitialization
 | 
			
		||||
    deInitialize_MCU();
 | 
			
		||||
//#endif
 | 
			
		||||
#ifdef DEINITIALIZE_AFTER_SIM
 | 
			
		||||
	// deinitialize app
 | 
			
		||||
	app_deinit();
 | 
			
		||||
// PERIPH DEINIT START
 | 
			
		||||
	deInitialize_Periph_Sim();
 | 
			
		||||
// PERIPH DEINIT END
 | 
			
		||||
#endif// DEINITIALIZE_AFTER_SIM
 | 
			
		||||
}
 | 
			
		||||
/* WORK WITH IN/OUT BUFFER OF S-BLOCK */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Функция для записи переменной в буфер выходов в определенный массив
 | 
			
		||||
  * @param xD           - указатель на буфер состояний
 | 
			
		||||
  * @param value        - значение для записи
 | 
			
		||||
  * @param array_index  - индекс выходного массива
 | 
			
		||||
  * @param value_index  - индекс внутри массива
 | 
			
		||||
  */
 | 
			
		||||
void __WriteOutputArray(real_T* xD, float value, int array_index, int value_index)
 | 
			
		||||
{
 | 
			
		||||
    if (array_index >= OUT_PORT_NUMB)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (value_index >= outLengths[array_index])
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    int global_index = XD_OUTPUT_START + outOffsets[array_index] + value_index;
 | 
			
		||||
    xD[global_index] = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Функция для чтения значения из буфера входов из определенного массива
 | 
			
		||||
  * @param xD           - указатель на буфер состояний
 | 
			
		||||
  * @param array_index  - индекс входного массива
 | 
			
		||||
  * @param value_index  - индекс внутри массива
 | 
			
		||||
  * @return             - считанное значение или 0.0 при выходе за границы
 | 
			
		||||
  */
 | 
			
		||||
float __ReadInputArray(const real_T* xD, int array_index, int value_index)
 | 
			
		||||
{
 | 
			
		||||
    if (array_index >= IN_PORT_NUMB)
 | 
			
		||||
        return 0.0f;
 | 
			
		||||
 | 
			
		||||
    if (value_index >= inLengths[array_index])
 | 
			
		||||
        return 0.0f;
 | 
			
		||||
 | 
			
		||||
    int global_index = XD_INPUT_START + inOffsets[array_index] + value_index;
 | 
			
		||||
    return xD[global_index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief      Формирование выходов S-Function.
 | 
			
		||||
 *	@param		S - указатель на структуру S-Function из "simstruc.h"
 | 
			
		||||
  * @details    Пользовательский код, который записывает выходы S-Function из буфера дискретных состояний.
 | 
			
		||||
  */
 | 
			
		||||
void SIM_writeOutputs(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
    real_T* Output = ssGetOutputPortRealSignal(S,0);
 | 
			
		||||
    real_T* Out_Buff = ssGetDiscStates(S);
 | 
			
		||||
    int global_index;
 | 
			
		||||
 | 
			
		||||
    //-------------WRITTING OUTPUT--------------
 | 
			
		||||
    for (int arr_ind = 0; arr_ind < OUT_PORT_NUMB; arr_ind++)
 | 
			
		||||
    {
 | 
			
		||||
        Output = ssGetOutputPortRealSignal(S, arr_ind);
 | 
			
		||||
        for (int val_ind = 0; val_ind < outLengths[arr_ind]; val_ind++)
 | 
			
		||||
        {
 | 
			
		||||
            global_index = XD_OUTPUT_START + outOffsets[arr_ind] + val_ind;
 | 
			
		||||
            Output[val_ind] = Out_Buff[global_index];
 | 
			
		||||
            Out_Buff[global_index] = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    //------------------------------------------
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
  * @brief      Формирование входов S-Function.
 | 
			
		||||
 *	@param		S - указатель на структуру S-Function из "simstruc.h"
 | 
			
		||||
  * @details    Пользовательский код, который считывает входы S-Function в буфер дискретных состояний.
 | 
			
		||||
  */
 | 
			
		||||
void SIM_readInputs(SimStruct* S)
 | 
			
		||||
{
 | 
			
		||||
    real_T* Input = ssGetInputPortRealSignal(S, 0);
 | 
			
		||||
    real_T* In_Buff = ssGetDiscStates(S);
 | 
			
		||||
    int global_index;
 | 
			
		||||
 | 
			
		||||
    //-------------READING INPUTS---------------
 | 
			
		||||
    for (int arr_ind = 0; arr_ind < IN_PORT_NUMB; arr_ind++)
 | 
			
		||||
    {
 | 
			
		||||
        Input = ssGetInputPortRealSignal(S, arr_ind);
 | 
			
		||||
        for (int val_ind = 0; val_ind < inLengths[arr_ind]; val_ind++)
 | 
			
		||||
        {
 | 
			
		||||
            global_index = XD_INPUT_START + inOffsets[arr_ind] + val_ind;
 | 
			
		||||
            In_Buff[global_index] = Input[val_ind];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    //------------------------------------------
 | 
			
		||||
}
 | 
			
		||||
//-------------------------------------------------------------//
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,11 @@
 | 
			
		||||
**************************************************************************
 | 
			
		||||
* @dir ../MCU_Wrapper
 | 
			
		||||
* @brief <b> Папка с исходным кодом оболочки МК. </b>
 | 
			
		||||
* @details
 | 
			
		||||
В этой папке содержаться оболочка(англ. wrapper) для запуска и контроля
 | 
			
		||||
эмуляции микроконтроллеров в MATLAB (любого МК, не только STM).
 | 
			
		||||
Оболочка представляет собой S-Function - блок в Simulink, который работает
 | 
			
		||||
по скомпилированому коду. Компиляция происходит с помощью MSVC-компилятора.
 | 
			
		||||
* @details 
 | 
			
		||||
В этой папке содержаться оболочка(англ. wrapper) для запуска и контроля 
 | 
			
		||||
эмуляции микроконтроллеров в MATLAB (любого МК, не только STM). 
 | 
			
		||||
Оболочка представляет собой S-Function - блок в Simulink, который работает 
 | 
			
		||||
по скомпилированому коду. Компиляция происходит с помощью MSVC-компилятора. 
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -25,56 +25,105 @@
 | 
			
		||||
#define _WRAPPER_CONF_H_
 | 
			
		||||
 | 
			
		||||
// Includes
 | 
			
		||||
#include "stm32f1xx_matlab_conf.h"  // For stm simulate functions
 | 
			
		||||
#include "simstruc.h"               // For S-Function variables
 | 
			
		||||
#include <process.h>                // For threads
 | 
			
		||||
 | 
			
		||||
#include "app_includes.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
    * @defgroup	MCU_WRAPPER     MCU Wrapper
 | 
			
		||||
    * @brief 		Всякое для оболочки МК
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
        * @addtogroup	WRAPPER_CONF    Wrapper Configuration
 | 
			
		||||
        * @ingroup		MCU_WRAPPER
 | 
			
		||||
        * @brief 		Параметры конфигурации для оболочки МК
 | 
			
		||||
        * @details		Здесь дефайнами задается параметры оболочки, которые определяют как она будет работать
 | 
			
		||||
        * @{
 | 
			
		||||
        */
 | 
			
		||||
/**
 | 
			
		||||
    * @addtogroup	WRAPPER_CONF    Wrapper Configuration
 | 
			
		||||
    * @ingroup		MCU_WRAPPER
 | 
			
		||||
    * @brief 		Параметры конфигурации для оболочки МК
 | 
			
		||||
    * @details		Здесь дефайнами задается параметры оболочки, которые определяют как она будет работать
 | 
			
		||||
    * @{
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
        // Parametrs of MCU simulator
 | 
			
		||||
// Parametrs of MCU simulator
 | 
			
		||||
//#define RUN_APP_MAIN_FUNC_THREAD                    ///< Enable using thread for MCU main() func
 | 
			
		||||
//#define DEKSTOP_CYCLES_FOR_MCU_APP      0xFF      ///< number of for() cycles after which MCU thread would be suspended 
 | 
			
		||||
//#define MCU_CORE_CLOCK                  72000000
 | 
			
		||||
//#define DEKSTOP_CYCLES_FOR_MCU_APP      0xFFFF      ///< number of for() cycles after which MCU thread would be suspended 
 | 
			
		||||
//#define MCU_CORE_CLOCK                  150000000   ///< MCU clock rate for simulation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//#define DEINITIALIZE_AFTER_SIM                    ///< Enable deinitializing structures at simulation ends
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define PORT_WIDTH                      16          ///< width of one port
 | 
			
		||||
#define PORT_NUMB                       3           ///< amount of ports
 | 
			
		||||
// Parameters of S_Function
 | 
			
		||||
#define NPARAMS                 1                           ///< number of input parametrs (only Ts)
 | 
			
		||||
#define IN_PORT_WIDTH           (9)                         ///< width of input ports
 | 
			
		||||
#define IN_PORT_NUMB            1                           ///< number of input ports
 | 
			
		||||
#define OUT_PORT_WIDTH          PORT_WIDTH                  ///< width of output ports
 | 
			
		||||
#define OUT_PORT_NUMB           PORT_NUMB                   ///< number of output ports
 | 
			
		||||
#define DISC_STATES_WIDTH       PORT_WIDTH*PORT_NUMB        ///< width of discrete states array
 | 
			
		||||
// INPUT/OUTPUTS PARAMS START
 | 
			
		||||
#define IN_PORT_NUMB           2
 | 
			
		||||
#define IN_PORT_1_WIDTH        3
 | 
			
		||||
#define IN_PORT_2_WIDTH        6
 | 
			
		||||
 | 
			
		||||
#define OUT_PORT_NUMB           3
 | 
			
		||||
#define OUT_PORT_1_WIDTH        16
 | 
			
		||||
#define OUT_PORT_2_WIDTH        16
 | 
			
		||||
#define OUT_PORT_3_WIDTH        16
 | 
			
		||||
 | 
			
		||||
// INPUT/OUTPUTS PARAMS END
 | 
			
		||||
/** WRAPPER_CONF
 | 
			
		||||
  * @}
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
    * @addtogroup	MCU_WRAPPER
 | 
			
		||||
    * @{
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    // Fixed parameters(?) of S_Function
 | 
			
		||||
/**
 | 
			
		||||
  * @addtogroup	MCU_WRAPPER
 | 
			
		||||
  * @{
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
/** @brief Записывает значение в выходной массив блока S-Function
 | 
			
		||||
  * @param _var_ Значение, которое необходимо записать (будет преобразовано в float)
 | 
			
		||||
  * @param _arr_ind_ Индекс выходного порта
 | 
			
		||||
  * @param _val_ind_ Индекс элемента в выходном массиве
 | 
			
		||||
  */
 | 
			
		||||
#define	WriteOutputArray(_var_, _arr_ind_, _val_ind_)	__WriteOutputArray(Buffer, (float)_var_, _arr_ind_, _val_ind_)
 | 
			
		||||
 | 
			
		||||
/** @brief Считывает значение из входного массива блока S-Function
 | 
			
		||||
  * @param _var_ Значение, которое необходимо записать (будет преобразовано в float)
 | 
			
		||||
  * @param _arr_ind_ Индекс входного порта
 | 
			
		||||
  * @param _val_ind_ Индекс элемента во входном массиве
 | 
			
		||||
  */
 | 
			
		||||
#define	ReadInputArray(_arr_ind_, _val_ind_)		__ReadInputArray(Buffer, _arr_ind_, _val_ind_)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// INPUT/OUTPUTS AUTO-PARAMS START
 | 
			
		||||
/// === Полный размер буфера ===
 | 
			
		||||
#define TOTAL_IN_SIZE (IN_PORT_1_WIDTH + IN_PORT_2_WIDTH)
 | 
			
		||||
 | 
			
		||||
/// === Смещения массивов (внутри общего буфера) ===
 | 
			
		||||
#define OFFSET_IN_ARRAY_1 0
 | 
			
		||||
#define OFFSET_IN_ARRAY_2 (OFFSET_IN_ARRAY_1 + IN_PORT_1_WIDTH)
 | 
			
		||||
 | 
			
		||||
/// === Полный размер буфера ===
 | 
			
		||||
#define TOTAL_OUT_SIZE (OUT_PORT_1_WIDTH + OUT_PORT_2_WIDTH + OUT_PORT_3_WIDTH)
 | 
			
		||||
 | 
			
		||||
/// === Смещения массивов (внутри общего буфера) ===
 | 
			
		||||
#define OFFSET_OUT_ARRAY_1 0
 | 
			
		||||
#define OFFSET_OUT_ARRAY_2 (OFFSET_OUT_ARRAY_1 + OUT_PORT_1_WIDTH)
 | 
			
		||||
#define OFFSET_OUT_ARRAY_3 (OFFSET_OUT_ARRAY_2 + OUT_PORT_2_WIDTH)
 | 
			
		||||
 | 
			
		||||
// INPUT/OUTPUTS AUTO-PARAMS END
 | 
			
		||||
 | 
			
		||||
extern const int outLengths[OUT_PORT_NUMB];
 | 
			
		||||
extern const int outOffsets[OUT_PORT_NUMB];
 | 
			
		||||
extern const int inLengths[IN_PORT_NUMB];
 | 
			
		||||
extern const int inOffsets[IN_PORT_NUMB];
 | 
			
		||||
#define TOTAL_XD_SIZE (TOTAL_IN_SIZE + TOTAL_OUT_SIZE)
 | 
			
		||||
#define XD_INPUT_START      0
 | 
			
		||||
#define XD_OUTPUT_START     (XD_INPUT_START + TOTAL_IN_SIZE)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Fixed parameters(?) of S_Function
 | 
			
		||||
#define NPARAMS                 1                               ///< number of input parametrs (only Ts)
 | 
			
		||||
#define DISC_STATES_WIDTH       OUT_PORT_WIDTH*OUT_PORT_NUMB    ///< width of discrete states array (outbup buffer)
 | 
			
		||||
#define DISC_STATES_WIDTH       TOTAL_XD_SIZE    ///< width of discrete states array (outbup buffer)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief      Define for creating thread in suspended state.
 | 
			
		||||
  * @details    Define from WinBase.h. We dont wanna include "Windows.h" or smth like this, because of HAL there are a lot of redefine errors.
 | 
			
		||||
@ -83,21 +132,23 @@
 | 
			
		||||
typedef void* HANDLE; ///< MCU handle typedef
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief  MCU handle Structure definition.
 | 
			
		||||
  * @brief  MCU handle Structure definition. 
 | 
			
		||||
  * @note 	Prefixes: h - handle, s - settings, f - flag
 | 
			
		||||
  */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    // MCU Thread
 | 
			
		||||
    HANDLE          hMCUThread;                 ///< Хендл для потока МК
 | 
			
		||||
    uint32_t        idMCUThread;                ///< id потока МК (unused)
 | 
			
		||||
    int             idMCUThread;                ///< id потока МК (unused)
 | 
			
		||||
    // Flags
 | 
			
		||||
    unsigned        fMCU_Stop : 1;              ///< флаг для выхода из потока программы МК
 | 
			
		||||
    double          SIM_Sample_Time;            ///< sample time of simulation
 | 
			
		||||
    unsigned        fInitDone : 1;              ///< флаг для выхода из потока программы МК
 | 
			
		||||
 | 
			
		||||
    double          SimTime;                    ///< Текущее время симуляции
 | 
			
		||||
    long            SystemClock;                ///< Счетчик тактов для симуляции системных тиков (в целочисленном формате)
 | 
			
		||||
 | 
			
		||||
    double          SystemClockDouble;          ///< Счетчик в формате double для точной симуляции системных тиков С промежуточными значений
 | 
			
		||||
    uint64_t        SystemClock;                ///< Счетчик тактов для симуляции системных тиков (в целочисленном формате)
 | 
			
		||||
    double          SystemClock_step;           ///< Шаг тиков для их симуляции, в формате double
 | 
			
		||||
    double          SimTime;
 | 
			
		||||
    double          sSystemClock_step;          ///< Шаг тиков для их симуляции, в формате double
 | 
			
		||||
    double          sSimSampleTime;             ///< Период дискретизации симуляции
 | 
			
		||||
}SIM__MCUHandleTypeDef;
 | 
			
		||||
extern SIM__MCUHandleTypeDef hmcu;              // extern для видимости переменной во всех файлах
 | 
			
		||||
 | 
			
		||||
@ -112,54 +163,62 @@ extern SIM__MCUHandleTypeDef hmcu;              // extern для видимос
 | 
			
		||||
  */
 | 
			
		||||
#define while(_expression_)                          sim_while(_expression_) 
 | 
			
		||||
#endif
 | 
			
		||||
  /* SIMULINK WHILE */
 | 
			
		||||
  /**
 | 
			
		||||
    * @brief      While statement for emulate MCU code in Simulink.
 | 
			
		||||
    * @param      _expression_ - expression for while.
 | 
			
		||||
    * @details    Данный while необходим, чтобы в конце симуляции, завершить поток МК:
 | 
			
		||||
    *             При выставлении флага окончания симуляции, все while будут пропускаться
 | 
			
		||||
    *             и поток сможет дойти до конца функции main и завершить себя.
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
/* SIMULINK WHILE */
 | 
			
		||||
/**
 | 
			
		||||
  * @brief      While statement for emulate MCU code in Simulink.
 | 
			
		||||
  * @param      _expression_ - expression for while.
 | 
			
		||||
  * @details    Данный while необходим, чтобы в конце симуляции, завершить поток МК:
 | 
			
		||||
  *             При выставлении флага окончания симуляции, все while будут пропускаться 
 | 
			
		||||
  *             и поток сможет дойти до конца функции main и завершить себя. 
 | 
			
		||||
  */    
 | 
			
		||||
#define sim_while(_expression_)                     while((_expression_)&&(hmcu.fMCU_Stop == 0))
 | 
			
		||||
 | 
			
		||||
    /* DEFAULT WHILE */
 | 
			
		||||
    /**
 | 
			
		||||
      * @brief      Default/Native C while statement.
 | 
			
		||||
      * @param      _expression_ - expression for while.
 | 
			
		||||
      * @details    Данный while - аналог обычного while, без дополнительного функционала.
 | 
			
		||||
      */
 | 
			
		||||
/* DEFAULT WHILE */
 | 
			
		||||
/**
 | 
			
		||||
  * @brief      Default/Native C while statement.
 | 
			
		||||
  * @param      _expression_ - expression for while.
 | 
			
		||||
  * @details    Данный while - аналог обычного while, без дополнительного функционала.
 | 
			
		||||
  */
 | 
			
		||||
#define native_while(_expression_)                   for(; (_expression_); )
 | 
			
		||||
      /***************************************************************/
 | 
			
		||||
  /***************************************************************/
 | 
			
		||||
 | 
			
		||||
    //------------------  SIMULINK WHILE DEFINES  -----------------//
 | 
			
		||||
    //-------------------------------------------------------------//
 | 
			
		||||
//------------------  SIMULINK WHILE DEFINES  -----------------//
 | 
			
		||||
//-------------------------------------------------------------//
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //-------------------------------------------------------------//
 | 
			
		||||
    //---------------- SIMULATE FUNCTIONS PROTOTYPES  -------------//
 | 
			
		||||
    /* Step simulation */
 | 
			
		||||
void MCU_Step_Simulation(SimStruct* S, time_T time);
 | 
			
		||||
//-------------------------------------------------------------//
 | 
			
		||||
//---------------- SIMULATE FUNCTIONS PROTOTYPES  -------------//
 | 
			
		||||
/* Step simulation */
 | 
			
		||||
void MCU_Step_Simulation(SimStruct *S, time_T time);     
 | 
			
		||||
 | 
			
		||||
/* MCU peripheral simulation */
 | 
			
		||||
void MCU_Periph_Simulation(void);
 | 
			
		||||
void MCU_Periph_Simulation(SimStruct* S);
 | 
			
		||||
 | 
			
		||||
/* Initialize MCU simulation */
 | 
			
		||||
void SIM_Initialize_Simulation(void);
 | 
			
		||||
void SIM_Initialize_Simulation(SimStruct* S);
 | 
			
		||||
 | 
			
		||||
/* Deinitialize MCU simulation */
 | 
			
		||||
void SIM_deInitialize_Simulation(void);
 | 
			
		||||
void SIM_deInitialize_Simulation(SimStruct* S);
 | 
			
		||||
 | 
			
		||||
/* Read inputs S-function  */
 | 
			
		||||
void MCU_readInputs(SimStruct* S);
 | 
			
		||||
void app_readInputs(real_T* in);
 | 
			
		||||
 | 
			
		||||
/* Write pre-outputs S-function (out_buff states) */
 | 
			
		||||
void MCU_writeOutputs(SimStruct* S);
 | 
			
		||||
void app_writeOutputBuffer(real_T* disc);
 | 
			
		||||
 | 
			
		||||
/* Write outputs of block of S-Function*/
 | 
			
		||||
void SIM_writeOutput(SimStruct* S);
 | 
			
		||||
void SIM_writeOutputs(SimStruct* S);
 | 
			
		||||
 | 
			
		||||
/* Write inputs of block of S-Function*/
 | 
			
		||||
void SIM_readInputs(SimStruct* S);
 | 
			
		||||
 | 
			
		||||
/* Set output of block of S-Function*/
 | 
			
		||||
void __WriteOutputArray(real_T* xD, float value, int array_index, int value_index);
 | 
			
		||||
 | 
			
		||||
/* Get input of block of S-Function*/
 | 
			
		||||
float __ReadInputArray(const real_T* xD, int array_index, int value_index);
 | 
			
		||||
//---------------- SIMULATE FUNCTIONS PROTOTYPES  -------------//
 | 
			
		||||
//-------------------------------------------------------------//
 | 
			
		||||
 | 
			
		||||
@ -169,14 +228,14 @@ void SIM_writeOutput(SimStruct* S);
 | 
			
		||||
#endif // _WRAPPER_CONF_H_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //-------------------------------------------------------------//
 | 
			
		||||
    //---------------------BAT FILE DESCRIBTION--------------------//
 | 
			
		||||
    /**
 | 
			
		||||
      * @file run_mex.bat
 | 
			
		||||
      * @brief Батник для компиляции оболочки МК.
 | 
			
		||||
      * @details
 | 
			
		||||
      * Вызывается в матлабе из mexing.m.
 | 
			
		||||
      *
 | 
			
		||||
      * Исходный код батника:
 | 
			
		||||
      * @include F:\Work\Projects\MATLAB\matlab_stm_emulate\MCU_Wrapper\run_mex.bat
 | 
			
		||||
      */
 | 
			
		||||
//-------------------------------------------------------------//
 | 
			
		||||
//---------------------BAT FILE DESCRIBTION--------------------//
 | 
			
		||||
/**
 | 
			
		||||
  * @file run_mex.bat
 | 
			
		||||
  * @brief Батник для компиляции оболочки МК.
 | 
			
		||||
  * @details
 | 
			
		||||
  * Вызывается в матлабе из allmex.m.
 | 
			
		||||
  * 
 | 
			
		||||
  * Исходный код батника:
 | 
			
		||||
  * @include run_mex.bat
 | 
			
		||||
  */
 | 
			
		||||
@ -1,718 +0,0 @@
 | 
			
		||||
% Компилирует 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
 | 
			
		||||
@ -11,33 +11,37 @@
 | 
			
		||||
:: %4 — режим компиляции (debug/release)
 | 
			
		||||
 | 
			
		||||
:: Сохраняем как переменные
 | 
			
		||||
set includes_USER=%~1
 | 
			
		||||
set code_USER=%~2
 | 
			
		||||
set defines_USER=%~3
 | 
			
		||||
set compil_mode=%~4
 | 
			
		||||
set filename=%~1
 | 
			
		||||
set includes_USER=%~2
 | 
			
		||||
set code_USER=%~3
 | 
			
		||||
set defines_USER=%~4
 | 
			
		||||
set defines_CONFIG=%~5
 | 
			
		||||
set compil_mode=%~6
 | 
			
		||||
 | 
			
		||||
:: Заменяем __EQ__ на =
 | 
			
		||||
set defines_USER=%defines_USER:__EQ__==%
 | 
			
		||||
set defines_CONFIG=%defines_CONFIG:__EQ__==%
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
set defines_WRAPPER=-D"MATLAB"^ -D"__sizeof_ptr=8"
 | 
			
		||||
 | 
			
		||||
:: -------------------------USERS PATHS AND CODE---------------------------
 | 
			
		||||
::-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
:: -----------------------MCU LIBRARIES & SIMULATOR------------------------
 | 
			
		||||
:: -----MCU LIBRARIES STUFF----
 | 
			
		||||
:: заголовочные файлы
 | 
			
		||||
set includes_MCU= -I".\MCU_STM32F1xx_Matlab"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_SIMULINK"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\CMSIS"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\CMSIS\Device\STM32F1xx"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Inc"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Inc\Legacy"
 | 
			
		||||
  
 | 
			
		||||
:: код библиотек МК, переделанный для матлаб
 | 
			
		||||
set code_MCU= .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc.c^
 | 
			
		||||
:: -------------------------WRAPPER PATHS AND CODE---------------------------
 | 
			
		||||
:: оболочка, которая будет моделировать работу МК в симулинке
 | 
			
		||||
set includes_WRAPPER=-I"."^
 | 
			
		||||
 -I".\MCU_Wrapper"^
 | 
			
		||||
 -I".\app_wrapper"
 | 
			
		||||
 | 
			
		||||
set code_WRAPPER= .\MCU_Wrapper\MCU.c^
 | 
			
		||||
 .\MCU_Wrapper\mcu_wrapper.c^
 | 
			
		||||
 .\app_wrapper\app_init.c^
 | 
			
		||||
 .\app_wrapper\app_io.c^
 | 
			
		||||
 .\app_wrapper\app_wrapper.c
 | 
			
		||||
 | 
			
		||||
:: PERIPH BAT START
 | 
			
		||||
set code_PERIPH=.\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_pwr.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_cortex.c^
 | 
			
		||||
@ -47,64 +51,56 @@ set code_MCU= .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim_ex.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_dma.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_exti.c
 | 
			
		||||
 | 
			
		||||
:: .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash_ramfunc.c^
 | 
			
		||||
:: .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash.c^
 | 
			
		||||
:: .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash_ex.c^
 | 
			
		||||
:: .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc_ex.c^
 | 
			
		||||
 | 
			
		||||
:: --------MCU SIMULATOR-------
 | 
			
		||||
:: код, которая будет симулировать перефирию МК в симулинке
 | 
			
		||||
set code_MCU_Sim= .\MCU_STM32F1xx_Matlab\stm32f1xx_matlab_conf.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_exti.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\stm32f1xx_matlab_conf.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_SIMULINK\stm32f1xx_matlab_gpio.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_SIMULINK\stm32f1xx_matlab_tim.c^
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_SIMULINK\stm32f1xx_periph_registers.c 
 | 
			
		||||
::-------------------------------------------------------------------------
 | 
			
		||||
 .\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_SIMULINK\stm32f1xx_periph_registers.c
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
:: -------------------------WRAPPER PATHS AND CODE---------------------------
 | 
			
		||||
:: оболочка, которая будет моделировать работу МК в симулинке
 | 
			
		||||
set includes_WRAPPER= -I".\MCU_Wrapper"
 | 
			
		||||
set code_WRAPPER= .\MCU_Wrapper\MCU.c^
 | 
			
		||||
 .\MCU_Wrapper\mcu_wrapper.c^
 | 
			
		||||
 .\MCU_Wrapper\app_wrapper.c
 | 
			
		||||
set includes_PERIPH=-I".\MCU_STM32F1xx_Matlab"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_SIMULINK"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\CMSIS"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\CMSIS\Device\STM32F1xx"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Inc"^
 | 
			
		||||
 -I".\MCU_STM32F1xx_Matlab\Drivers\STM32F1xx_HAL_Driver\Inc\Legacy"
 | 
			
		||||
:: PERIPH BAT END
 | 
			
		||||
::-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
:: ---------------------SET PARAMS FOR MEX COMPILING-----------------------
 | 
			
		||||
:: --------ALL INCLUDES--------
 | 
			
		||||
set includes= %includes_USER% %includes_MCU% %includes_WRAPPER%
 | 
			
		||||
set codes= %code_WRAPPER% %code_USER% %code_MCU% %code_MCU_Sim%
 | 
			
		||||
set defines= %defines_USER% %defines_WRAPPER%
 | 
			
		||||
:: -------------ALL------------
 | 
			
		||||
set includes= %includes_WRAPPER% %includes_PERIPH% %includes_USER%
 | 
			
		||||
set codes= %code_WRAPPER% %code_PERIPH% %code_USER%
 | 
			
		||||
set defines= %defines_WRAPPER% %defines_CONFIG% %defines_USER%
 | 
			
		||||
:: -------OUTPUT FOLDER--------
 | 
			
		||||
set output= -outdir "."
 | 
			
		||||
set output= -outdir "." -output %filename%
 | 
			
		||||
 | 
			
		||||
:: если нужен дебаг, до запускаем run mex с припиской debug
 | 
			
		||||
IF %compil_mode%==[debug] (set debug= -g)
 | 
			
		||||
:: если нужен дебаг, до запускаем run_mex с припиской debug
 | 
			
		||||
IF %compil_mode%==debug (set debug= -g)
 | 
			
		||||
::-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
::------START COMPILING-------    
 | 
			
		||||
if "%5"=="echo_enable" (
 | 
			
		||||
if "%7"=="echo_enable" (
 | 
			
		||||
    echo Compiling...
 | 
			
		||||
 | 
			
		||||
    echo ===========================
 | 
			
		||||
    echo INCLUDES:
 | 
			
		||||
    echo =========INCLUDES==========
 | 
			
		||||
    echo USER:
 | 
			
		||||
    for %%f in (%includes_USER%) do (
 | 
			
		||||
        echo   %%f
 | 
			
		||||
    )
 | 
			
		||||
    echo INTERNAL:
 | 
			
		||||
    for %%f in (%includes_MCU%) do (
 | 
			
		||||
    for %%f in (%includes_WRAPPER%) do (
 | 
			
		||||
        echo   %%f
 | 
			
		||||
    )
 | 
			
		||||
    for %%f in (%includes_WRAPPER%) do (
 | 
			
		||||
    echo PERIPH:
 | 
			
		||||
    for %%f in (%includes_PERIPH%) do (
 | 
			
		||||
        echo   %%f
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    echo ===========================
 | 
			
		||||
    echo SOURCES:
 | 
			
		||||
    echo ==========SOURCES==========
 | 
			
		||||
    echo USER:
 | 
			
		||||
    for %%f in (%code_USER%) do (
 | 
			
		||||
        echo   %%f
 | 
			
		||||
@ -113,19 +109,21 @@ if "%5"=="echo_enable" (
 | 
			
		||||
    for %%f in (%code_WRAPPER%) do (
 | 
			
		||||
        echo   %%f
 | 
			
		||||
    )
 | 
			
		||||
    for %%f in (%code_MCU_Sim%) do (
 | 
			
		||||
        echo   %%f
 | 
			
		||||
    )
 | 
			
		||||
    for %%f in (%code_MCU%) do (
 | 
			
		||||
    echo PERIPH:
 | 
			
		||||
    for %%f in (%code_PERIPH%) do (
 | 
			
		||||
        echo   %%f
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    echo ===========================
 | 
			
		||||
    echo DEFINES:
 | 
			
		||||
    echo ==========DEFINES==========
 | 
			
		||||
    echo USER:
 | 
			
		||||
    for %%d in (%defines_USER%) do (
 | 
			
		||||
        echo   %%d
 | 
			
		||||
    )
 | 
			
		||||
    echo CONFIG:
 | 
			
		||||
    for %%f in (%defines_CONFIG%) do (
 | 
			
		||||
        echo   %%f
 | 
			
		||||
    )
 | 
			
		||||
    echo INTERNAL:
 | 
			
		||||
    for %%f in (%defines_WRAPPER%) do (
 | 
			
		||||
        echo   %%f
 | 
			
		||||
@ -134,6 +132,6 @@ if "%5"=="echo_enable" (
 | 
			
		||||
echo ===========================
 | 
			
		||||
echo MODE: %compil_mode%
 | 
			
		||||
echo ===========================
 | 
			
		||||
 | 
			
		||||
mex %output% %defines% %includes% %codes% %debug%
 | 
			
		||||
echo %DATE% %TIME%
 | 
			
		||||
echo %DATE% %TIME%
 | 
			
		||||
exit /b %ERRORLEVEL%
 | 
			
		||||
							
								
								
									
										10
									
								
								app_wrapper/app_configs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app_wrapper/app_configs.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
/**
 | 
			
		||||
**************************************************************************
 | 
			
		||||
* @file app_config.h
 | 
			
		||||
* @brief Заголовочный файл для пользовательских конфигураций.
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
#ifndef _APP_CONFIG
 | 
			
		||||
#define _APP_CONFIG
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //_APP_CONFIG
 | 
			
		||||
							
								
								
									
										18
									
								
								app_wrapper/app_includes.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app_wrapper/app_includes.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
/**
 | 
			
		||||
**************************************************************************
 | 
			
		||||
* @file app_includes.h
 | 
			
		||||
* @brief Заголовочный файл для подключаения заголовочных файлов программы МК.
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
#ifndef _APP_INCLUDES_H_
 | 
			
		||||
#define _APP_INCLUDES_H_
 | 
			
		||||
 | 
			
		||||
#include "app_configs.h"
 | 
			
		||||
 | 
			
		||||
// INCLUDES START
 | 
			
		||||
// Инклюды для доступа к коду МК в коде оболочке
 | 
			
		||||
//#include "stm32f1xx_matlab_conf.h"
 | 
			
		||||
#include "upp.h"
 | 
			
		||||
#include "main.h"
 | 
			
		||||
// INCLUDES END
 | 
			
		||||
 | 
			
		||||
#endif //_APP_INCLUDES_H_
 | 
			
		||||
							
								
								
									
										38
									
								
								app_wrapper/app_init.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								app_wrapper/app_init.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
/**
 | 
			
		||||
**************************************************************************
 | 
			
		||||
* @file app_init.h
 | 
			
		||||
* @brief Файл с функцией инициализации программы МК @ref app_init.
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
#include "app_wrapper.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Функция для инициализации приложения МК
 | 
			
		||||
  * @details Используется в случае симуляции без отдельного потока для main().
 | 
			
		||||
  */
 | 
			
		||||
void app_init(void) {
 | 
			
		||||
// USER APP INIT START
 | 
			
		||||
// Код для инициализации приложения МК
 | 
			
		||||
//
 | 
			
		||||
// Вызов разных функций в случае, 
 | 
			
		||||
// если не используется отдельный поток для main().
 | 
			
		||||
HAL_Init();
 | 
			
		||||
MX_GPIO_Init();
 | 
			
		||||
MX_TIM2_Init();
 | 
			
		||||
upp_init();
 | 
			
		||||
// USER APP INIT END
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Функция для деинициализации приложения МК
 | 
			
		||||
  */
 | 
			
		||||
void app_deinit(void) {
 | 
			
		||||
// USER APP DEINIT START
 | 
			
		||||
// Код для деинициализации приложения МК
 | 
			
		||||
//
 | 
			
		||||
// Структуры, переменные и так далее, которые надо очистить,
 | 
			
		||||
// для повторного запуска симуляции.
 | 
			
		||||
deInitialize_MCU();
 | 
			
		||||
// USER APP DEINIT END
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								app_wrapper/app_io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								app_wrapper/app_io.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
			
		||||
/**
 | 
			
		||||
**************************************************************************
 | 
			
		||||
* @file app_init.h
 | 
			
		||||
* @brief Файл с функциями записи входов/выходов программы МК @ref app_init.
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
#include "app_wrapper.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Функция для записи входов в приложение МК
 | 
			
		||||
  * @param u - массив входных значений
 | 
			
		||||
  */
 | 
			
		||||
void app_readInputs(const real_T* Buffer) {
 | 
			
		||||
// USER APP INPUT START
 | 
			
		||||
// Код для записи считывания входов из IO буфера
 | 
			
		||||
// Буфер в начале хранит входные порты S-Function, далее идут выходные порты:
 | 
			
		||||
// Buffer[0:15] - входной 1 порт, Buffer[16:31] - входной 2 порт, 
 | 
			
		||||
// Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт
 | 
			
		||||
//
 | 
			
		||||
// Note: используте для чтения:
 | 
			
		||||
//    val = ReadInputArray(arr_ind, val_ind)
 | 
			
		||||
// Пример:
 | 
			
		||||
// // запись в второй элемент первого массива
 | 
			
		||||
// app_variable = ReadInputArray(0, 1);
 | 
			
		||||
// // чтение из IO буфера напрямую
 | 
			
		||||
// app_variable_2 = Buffer[10];
 | 
			
		||||
 | 
			
		||||
#define detect_front(_in_numb_, _var_, _val_) {                 \
 | 
			
		||||
if ((Buffer[_in_numb_] > 0.5) && (prev_in[_in_numb_] <= 0.5))   \
 | 
			
		||||
{                                                               \
 | 
			
		||||
    _var_ = _val_;                                              \
 | 
			
		||||
} }
 | 
			
		||||
 | 
			
		||||
#define detect_rise(_in_numb_, _var_, _val_) {                  \
 | 
			
		||||
if ((Buffer[_in_numb_] < 0.5) && (prev_in[_in_numb_] >= 0.5))   \
 | 
			
		||||
{                                                               \
 | 
			
		||||
    _var_ = _val_;                                              \
 | 
			
		||||
} }
 | 
			
		||||
 | 
			
		||||
    static real_T prev_in[TOTAL_IN_SIZE];
 | 
			
		||||
 | 
			
		||||
    detect_front(0, phase_A.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
    detect_rise(0, phase_A.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
 | 
			
		||||
    detect_front(1, phase_B.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
    detect_rise(1, phase_B.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
 | 
			
		||||
    detect_front(2, phase_C.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
    detect_rise(2, phase_C.zc_detector.f.EXTIZeroCrossDetected, 1);
 | 
			
		||||
 | 
			
		||||
    detect_front(3, Upp.GoSafe, 1);
 | 
			
		||||
    detect_rise(3, Upp.GoSafe, 0);
 | 
			
		||||
 | 
			
		||||
    detect_front(4, Upp.Prepare, 1);
 | 
			
		||||
    detect_rise(4, Upp.Prepare, 0);
 | 
			
		||||
 | 
			
		||||
    detect_front(5, Upp.ForceStop, 1);
 | 
			
		||||
    detect_rise(5, Upp.ForceStop, 0);
 | 
			
		||||
 | 
			
		||||
    detect_front(6, Upp.ForceDisconnect, 1);
 | 
			
		||||
    detect_rise(6, Upp.ForceDisconnect, 0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Upp.sine_freq = Buffer[7];
 | 
			
		||||
    Upp.Duration = Buffer[8];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < TOTAL_IN_SIZE; i++)
 | 
			
		||||
    {
 | 
			
		||||
        prev_in[i] = Buffer[i];
 | 
			
		||||
    }
 | 
			
		||||
// USER APP INPUT END
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Функция для записи выходов приложения МК
 | 
			
		||||
  * @param xD - массив буффера выходов(дискретных выходов)
 | 
			
		||||
  * @details Используте WriteOutputArray(val, arr_ind, val_ind) для записи
 | 
			
		||||
  */
 | 
			
		||||
void app_writeOutputBuffer(real_T* Buffer) {
 | 
			
		||||
// USER APP OUTPUT START
 | 
			
		||||
// Код для записи выходов в IO буфер
 | 
			
		||||
// Буфер в начале хранит входные порты S-Function, далее идут выходные порты:
 | 
			
		||||
// Buffer[0:15] - входной 1 порт, Buffer[16:31] - входной 2 порт, 
 | 
			
		||||
// Buffer[32:47] - выходной 1 порт, Buffer[48:63] - выходной 2 порт
 | 
			
		||||
//
 | 
			
		||||
// Note: используте для записи:
 | 
			
		||||
//    WriteOutputArray(val, arr_ind, val_ind)
 | 
			
		||||
// Пример:
 | 
			
		||||
// // запись в второй элемент первого массива
 | 
			
		||||
// WriteOutputArray(app_variable, 0, 1);
 | 
			
		||||
// // запись в IO буфер напрямую
 | 
			
		||||
// Buffer[XD_OUTPUT_START + 10] = app_variable_2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 16; i++)
 | 
			
		||||
    {
 | 
			
		||||
        if (GPIOA->ODR & (1 << i))
 | 
			
		||||
        {
 | 
			
		||||
            WriteOutputArray(1, 0, i);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            WriteOutputArray(0, 0, i);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (GPIOB->ODR & (1 << i))
 | 
			
		||||
        {
 | 
			
		||||
            WriteOutputArray(1, 1, i);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            WriteOutputArray(0, 1, i);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
int var = phase_A.ctrl.angle.delay_us;
 | 
			
		||||
WriteOutputArray(var, 2, 0);
 | 
			
		||||
var = (uint16_t)((uint16_t)TIMER->CNT - phase_A.ctrl.angle.start_delay_tick);
 | 
			
		||||
WriteOutputArray(var, 2, 1);
 | 
			
		||||
var = phase_A.ctrl.angle.start_delay_tick;
 | 
			
		||||
WriteOutputArray(var, 2, 2);
 | 
			
		||||
var = TIMER->CNT;
 | 
			
		||||
WriteOutputArray(var, 2, 3);
 | 
			
		||||
// USER APP OUTPUT END
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								app_wrapper/app_wrapper.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								app_wrapper/app_wrapper.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
#include "mcu_wrapper_conf.h"
 | 
			
		||||
#include "app_wrapper.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * @brief Функция для симуляции шага приложения МК
 | 
			
		||||
  * @details Используется в случае симуляции без отдельного потока для main().
 | 
			
		||||
  */
 | 
			
		||||
void app_step(void)
 | 
			
		||||
{
 | 
			
		||||
// USER APP STEP START
 | 
			
		||||
// Код приложения МК для вызова в шаге симуляции
 | 
			
		||||
//
 | 
			
		||||
// Вызов разных функций на шаге симуляции в случае, 
 | 
			
		||||
// если не используется отдельный поток для main().
 | 
			
		||||
uwTick = hmcu.SystemClock / (MCU_CORE_CLOCK / 1000);
 | 
			
		||||
 | 
			
		||||
upp_main();
 | 
			
		||||
// USER APP STEP END
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// DUMMY START
 | 
			
		||||
// Заглушки для различных функций и переменных
 | 
			
		||||
 | 
			
		||||
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk) {}
 | 
			
		||||
void SystemClock_Config(void) {}
 | 
			
		||||
void Error_Handler(void) {}
 | 
			
		||||
// DUMMY END
 | 
			
		||||
							
								
								
									
										12
									
								
								app_wrapper/app_wrapper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app_wrapper/app_wrapper.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _APP_WRAPPER_H_
 | 
			
		||||
#define _APP_WRAPPER_H_
 | 
			
		||||
 | 
			
		||||
#include "app_includes.h"
 | 
			
		||||
 | 
			
		||||
void app_step(void);
 | 
			
		||||
void app_init(void);
 | 
			
		||||
void app_deinit(void);
 | 
			
		||||
void app_readInputs(const real_T* u);
 | 
			
		||||
void app_writeOutputBuffer(real_T* xD);
 | 
			
		||||
 | 
			
		||||
#endif //_APP_WRAPPER_H_
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								mcu_test_r2023.slx.autosave
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mcu_test_r2023.slx.autosave
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										734
									
								
								mexing.asv
									
									
									
									
									
								
							
							
						
						
									
										734
									
								
								mexing.asv
									
									
									
									
									
								
							@ -1,734 +0,0 @@
 | 
			
		||||
% Компилирует 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 = 'configTabAll';  % Имя вкладки (Prompt)
 | 
			
		||||
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    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);
 | 
			
		||||
        % Получаем имя параметра из контрола
 | 
			
		||||
        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()
 | 
			
		||||
    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
 | 
			
		||||
							
								
								
									
										738
									
								
								mexing.m
									
									
									
									
									
								
							
							
						
						
									
										738
									
								
								mexing.m
									
									
									
									
									
								
							@ -1,738 +0,0 @@
 | 
			
		||||
% Компилирует 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 = 'configTabAll';  % Имя вкладки (Prompt)
 | 
			
		||||
 | 
			
		||||
    allControls = mask.getDialogControls();
 | 
			
		||||
    tabCtrl = find_container_by_name(allControls, tabName);
 | 
			
		||||
 | 
			
		||||
    if isempty(tabCtrl)
 | 
			
		||||
        error('Вкладка с названием "%s" не найдена в маске', tabName);
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    params = collect_all_parameters(tabCtrl);
 | 
			
		||||
    definesWrapperArg = '';
 | 
			
		||||
    for i = 1:numel(params)
 | 
			
		||||
        % Получаем имя параметра из контрола
 | 
			
		||||
        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);
 | 
			
		||||
        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()
 | 
			
		||||
    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,252 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "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": 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