/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "system_init.h"
#include "system_display.h"
#include "system_input.h"
#include "system_app.h"
#include "system_menu.h"
#include "buzzer.h"
#include "time_manager.h"
#include "uart_comm.h"
#include "pid_control.h"
#include "fuzzy_pid.h"
#include "env_simulator.h"
#include "cmd_handler.h"
#include "app_globals.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
I2C_HandleTypeDef hi2c2;
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart1;

PCD_HandleTypeDef hpcd_USB_FS;

/* USER CODE BEGIN PV */
/* 全局句柄 — 通过 app_globals.h 供所有模块访问 */
PID_Handle_t    g_pid;
EnvSim_Handle_t g_env;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_USB_PCD_Init(void);
static void MX_I2C1_Init(void);
static void MX_I2C2_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(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_SPI1_Init();
  MX_USB_PCD_Init();
  MX_I2C1_Init();
  MX_I2C2_Init();
  MX_USART1_Init();
  /* USER CODE BEGIN 2 */
  
  // 系统初始化
  if (System_Init_All() != HAL_OK) {
    Error_Handler();
  }
  
  // 输入模块初始化
  if (Input_Init() != HAL_OK) {
    Error_Handler();
  }
  
  // 应用模块初始化(绑定g_env作为统一数据源)
  if (App_Init_WithSim(&g_env) != HAL_OK) {
    Error_Handler();
  }

  // 串口通信初始化
  UART_Comm_Init();

  /* PID控制器初始化 (论文5.5.1节初始参数: Kp0=3.0, Ki0=0.5, Kd0=1.0) */
  PID_Init(&g_pid, 3.0f, 0.5f, 1.0f);
  /* 设置初始输入参数:T_surface初始值与环境温度一致 */
  PID_SetInput(&g_pid, -5.0f, -5.0f, 60.0f, 5.0f);  /* T_env, T_surface, H, W */
  /* 自动启动PID(仿真模式下无需手动发命令) */
  PID_Start(&g_pid);

  /* 环境模拟器初始化 */
  EnvSim_Init(&g_env, -5.0f, 60.0f, 5.0f);

  /* 命令处理器初始化 */
  CmdHandler_Init(&g_pid, &g_env);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    
    // 蜂鸣器定时处理
    Buzzer_HandleTypeDef *buzzer = System_Get_Buzzer();
    if (buzzer != NULL) {
        Buzzer_Process(buzzer);
    }
    
    // 时间同步处理
    TimeManager_Sync();
    
    // 运行应用主循环
    if (App_Run() != HAL_OK) {
      Error_Handler();
    }

    // 串口接收处理 + 命令解析
    CmdHandler_Process();

    /* 环境模拟器更新 */
    EnvSim_Process(&g_env);

    /* 将模拟器当前参数同步到PID输入(环境温度/湿度/风速直接从env_sim读取) */
    g_pid.input.t_env      = g_env.t_env;
    g_pid.input.humidity   = g_env.humidity;
    g_pid.input.wind_speed = g_env.wind_speed;

    /* PID控制器计算 */
    /* STOPPED状态下:若T_surface再次低于重启阈值(0°C),自动重启 */
    if (g_pid.state == PID_STATE_STOPPED &&
        g_pid.input.t_surface < PID_RESTART_TEMP) {
        g_pid.state     = PID_STATE_RUNNING;
        g_pid.last_tick = HAL_GetTick();
    }
    PID_Process(&g_pid);

    // 串口上报:数据变化时立即发送,无变化时5秒心跳一次
    {
        static uint32_t last_uart_report = 0;
        static uint32_t last_pid_report  = 0;
        static int16_t  last_temp  = 0x7FFF;
        static uint8_t  last_humi  = 0xFF;
        static uint16_t last_wind  = 0xFFFF;
        static uint8_t  last_sec   = 0xFF;

        uint32_t now_ms   = HAL_GetTick();
        int16_t  cur_temp = App_Get_Temperature();
        uint8_t  cur_humi = App_Get_Humidity();
        uint16_t cur_wind = App_Get_WindSpeed();
        System_Config_t* cfg = Menu_Get_Config();
        uint8_t  cur_sec  = (cfg != NULL) ? cfg->system_time.second : 0;

        /* 基础数据:有变化或5秒超时发送 */
        uint8_t changed = (cur_temp != last_temp ||
                           cur_humi != last_humi ||
                           cur_wind != last_wind ||
                           cur_sec  != last_sec);
        if (changed || (now_ms - last_uart_report) >= 5000) {
            HAL_StatusTypeDef uart_ret = UART_Comm_Printf(
                "T:%d H:%d W:%d Time:%02d:%02d:%02d\r\n",
                cur_temp, cur_humi, cur_wind,
                (cfg != NULL) ? cfg->system_time.hour   : 0,
                (cfg != NULL) ? cfg->system_time.minute : 0,
                cur_sec);
            App_Set_UartTxStatus(uart_ret == HAL_OK ? 1 : 0);
            last_temp = cur_temp;
            last_humi = cur_humi;
            last_wind = cur_wind;
            last_sec  = cur_sec;
            last_uart_report = now_ms;
        }

        /* PID数据:每1秒独立上报,不依赖基础数据变化 */
        if ((now_ms - last_pid_report) >= 1000) {
            /* 计算当前结冰速率和加热功率(n_ice 只依赖环境温度,t_surface 不影响结果) */
            IcingParams_t ip;
            Fuzzy_CalcIcingParams(g_pid.input.t_env,
                                  g_pid.input.wind_speed,
                                  g_pid.input.humidity,
                                  g_pid.input.t_surface, &ip);
            UART_Comm_Printf(
                "PID state:%d Tenv:%.1f Tsurf:%.2f H:%.1f W:%.1f "
                "mdot:%.5f Pff:%.1f Pdyn:%.1f "
                "e:%.3f I:%.3f D:%.3f Kp:%.3f Ki:%.3f Kd:%.3f P:%.2f\r\n",
                (int)g_pid.state,
                g_pid.input.t_env,
                g_pid.input.t_surface,
                g_pid.input.humidity,
                g_pid.input.wind_speed,
                ip.m_dot, ip.p_ff, ip.p_dyn,
                g_pid.process.error,
                g_pid.process.integral,
                g_pid.process.derivative,
                g_pid.process.kp,
                g_pid.process.ki,
                g_pid.process.kd,
                g_pid.process.output);
            last_pid_report = now_ms;
        }
    }
    HAL_Delay(10);  /* 10ms延迟,减少CPU占用 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_ENABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

/**
  * @brief I2C2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C2_Init(void)
{

  /* USER CODE BEGIN I2C2_Init 0 */

  /* USER CODE END I2C2_Init 0 */

  /* USER CODE BEGIN I2C2_Init 1 */

  /* USER CODE END I2C2_Init 1 */
  hi2c2.Instance = I2C2;
  hi2c2.Init.ClockSpeed = 100000;
  hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c2.Init.OwnAddress1 = 0;
  hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c2.Init.OwnAddress2 = 0;
  hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_ENABLE;
  if (HAL_I2C_Init(&hi2c2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C2_Init 2 */

  /* USER CODE END I2C2_Init 2 */

}

/**
  * @brief SPI1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

/**
  * @brief USB Initialization Function
  * @param None
  * @retval None
  */
static void MX_USB_PCD_Init(void)
{

  /* USER CODE BEGIN USB_Init 0 */

  /* USER CODE END USB_Init 0 */

  /* USER CODE BEGIN USB_Init 1 */

  /* USER CODE END USB_Init 1 */
  hpcd_USB_FS.Instance = USB;
  hpcd_USB_FS.Init.dev_endpoints = 8;
  hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
  hpcd_USB_FS.Init.low_power_enable = DISABLE;
  hpcd_USB_FS.Init.lpm_enable = DISABLE;
  hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
  if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USB_Init 2 */

  /* USER CODE END USB_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  /* USER CODE BEGIN MX_GPIO_Init_1 */

  /* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|SEG_CLK_Pin|SEG_DIO1_Pin|SEG_DIO2_Pin|SEG_DIO3_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);

  /*Configure GPIO pins : ENC1_S1_Pin ENC1_KEY_Pin */
  GPIO_InitStruct.Pin = ENC1_S1_Pin|ENC1_KEY_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : ENC1_S2_Pin */
  GPIO_InitStruct.Pin = ENC1_S2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(ENC1_S2_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : SD_CS_Pin */
  GPIO_InitStruct.Pin = SD_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : SEG_CLK_Pin SEG_DIO1_Pin SEG_DIO2_Pin SEG_DIO3_Pin */
  GPIO_InitStruct.Pin = SEG_CLK_Pin|SEG_DIO1_Pin|SEG_DIO2_Pin|SEG_DIO3_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : ENC2_S1_Pin */
  GPIO_InitStruct.Pin = ENC2_S1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(ENC2_S1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : ENC2_S2_Pin (PB8) */
  GPIO_InitStruct.Pin = ENC2_S2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(ENC2_S2_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : ENC2_KEY_Pin (PB9) - 外部中断 */
  GPIO_InitStruct.Pin = ENC2_KEY_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(ENC2_KEY_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : BUZZER_Pin */
  GPIO_InitStruct.Pin = BUZZER_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(BUZZER_GPIO_Port, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);

  HAL_NVIC_SetPriority(EXTI2_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(EXTI2_IRQn);

  HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

  /* ENC2_KEY 移至 PB9,同属 EXTI9_5,已在上方启用 */

  /* USER CODE BEGIN MX_GPIO_Init_2 */
  
  // 设置SD卡CS引脚为高电平(不选中状态)
  HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET);

  /* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/**
 * @brief  USART1 初始化 (PA9=TX, PA10=RX, 115200 8N1)
 * @retval None
 */
static void MX_USART1_Init(void)
{
    huart1.Instance          = USART1;
    huart1.Init.BaudRate     = 115200;
    huart1.Init.WordLength   = UART_WORDLENGTH_8B;
    huart1.Init.StopBits     = UART_STOPBITS_1;
    huart1.Init.Parity       = UART_PARITY_NONE;
    huart1.Init.Mode         = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart1) != HAL_OK) {
        Error_Handler();
    }
    /* 启用 USART1 全局中断 */
    HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
}

/**
 * @brief  GPIO外部中断回调函数
 * @param  GPIO_Pin: 触发中断的GPIO引脚
 * @retval None
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  static uint32_t last_encoder_time = 0;
  uint32_t current_time = HAL_GetTick();
  
  // 获取蜂鸣器句柄
  Buzzer_HandleTypeDef *buzzer = System_Get_Buzzer();
  
  // 蜂鸣器反馈处理
  if (buzzer != NULL) {
    switch (GPIO_Pin) {
        case ENC1_S1_Pin:
        case ENC2_S1_Pin:
            // 编码器旋转中断 - 防抖处理
            if (current_time - last_encoder_time > 50) {
                Buzzer_Encoder_Feedback(buzzer);
                last_encoder_time = current_time;
            }
            break;
            
        case ENC1_KEY_Pin:
        case ENC2_KEY_Pin:
            /* 按键中断:只在按下时(低电平)响一次,加防抖避免重复触发 */
            if ((current_time - last_encoder_time) > 200) {
                if (HAL_GPIO_ReadPin(
                        (GPIO_Pin == ENC1_KEY_Pin) ? ENC1_KEY_GPIO_Port : ENC2_KEY_GPIO_Port,
                        GPIO_Pin) == GPIO_PIN_RESET) {
                    Buzzer_Key_Feedback(buzzer);
                    last_encoder_time = current_time;
                }
            }
            break;
            
        default:
            break;
    }
  }
  
  // 委托给输入处理模块
  Input_IRQ_Handler(GPIO_Pin);
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

代码归档.zip