/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 *
 *          Must update the version and date information in "flash.h"         *
 *          Must update the version and date information in "flash.h"         *
 *          Must update the version and date information in "flash.h"         *
 *
 ******************************************************************************
 * edit            :    HwangSungWoo
 * date            :    5/7
 * FW              :    RoomFitMCU_v1
 *                    -> 이제부터 GitHub으로 버전관리!!
 * Original FW     :    RF_v1.0.1_250630_ForceWinding
 * PCB HW          :    v5
 * Machine         :
 * Temporary       :
 *    1.
 * Goal            :    출고 버전 (경미한 수정은 R1등으로 할지도 모르겠으나..)
 *     1.   지금 상태로 일단 가보자.......
 *     2.   EEPROMDATA 구조체에 여분 변수들 미리 확보 - 포기..
 * Key change      :
 *     1.
 *     2.
 * etc.            :
 *     1.
 * <Open Issues>
 *     1.  수행 시간 부족 문제 해결한 것 추적 관찰 (모터 교번 구동)
 *     2.  RegenR 로직에서 부동소수점 최소화 함 -> 기능 검증 안했음
 *     3.  F_xx들과 I_xx들을 실제 단위 kg, A에 맞게 바꿔야 하는 걸 임시로 했는데 완전히 처리된 지 모름
 *     4.  사실상 "ForcedWinding()" 함수 추가한 게 전부.
 *        - 이 마저도 기능 검증은 전혀 해보지 않았음
*      5. Derating 이어서 진행 : Timestamp Flash저장하기 구현해야 함
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 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"
#include "adc.h"
#include "dac.h"
#include "dma.h"
#include "i2c.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "usb_otg.h"
#include "gpio.h"
#include "flash.h"
#include "stm32f4xx.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "WESPION.h"
#include "WSPN_Security.h"
#include "led.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define TIMCLCOCK   180000000
#define PRESCALAR   180
#define PERIOD      100   //us

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
//#define __DEBUG__

#ifdef  __DEBUG__
#define DEBUG_printf                UART3_printf
#else
#define DEBUG_printf                Dummy_printf
#endif
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void PeriphCommonClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//uint32_t Dac1, Dac2;
//stm32f4xx_hal.c
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /* Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {
    return HAL_ERROR;
  }

  /* Configure the SysTick IRQ priority */
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    return HAL_ERROR;
  }

  /* Return function status */
  return HAL_OK;
}

int check_While, check_Dac;
WP_DriveStatus Drive_Status = EncInit; // 항상 EncInit -> Calibration -> RunGym으로 넘어가는 구조 - WESPION_Def.h 참고
WP_ActiveMotorStat Debug_DriveMotor = Drv_NoMotor;
uint8_t Debug_SkipEncInit = 0;  // [v1.0.3] 앱에서 EncInit 우회 (디버그용)
//WP_DriveStatus Drive_Status = RunGym;
//WP_ActiveMotorStat Debug_DriveMotor = Drv_BothMotor;

//WP_GeneralStatus AngleCali_Status = NotDone;

int MotorCurrCtrl_Alternating = 1;    //  모터 교번구동 여부 : 할거면 1


int Debug_Calib=3;
uint8_t SW1_new, SW1_old, SW1_State;
int First_Init_ADC_IDC = 0;
int Time;
float I_CHG;
uint8_t ATname[] = "RoomFit #";
uint8_t ATmacaddr[4];
uint8_t AT9600[] = "9600";
uint8_t AT115200[] = "115200";
int Debug_ATCommand;

int cnt_Welcome = 0;
int debug_LED_Color = 0;
uint8_t debug_LED_R,debug_LED_G,debug_LED_B;

uint8_t DebugingPrintActive = 0;

uint8_t InitialPosCali = 0;

uint8_t MotorInitStart = 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();

  /* Configure the peripherals common clocks */
  PeriphCommonClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_DAC_Init();
  MX_I2C1_Init();
  MX_SPI1_Init();
  MX_SPI4_Init();
  MX_TIM1_Init();
  MX_TIM4_Init();
  MX_TIM8_Init();
  MX_TIM9_Init();
  MX_USART2_UART_Init();
  MX_USART3_UART_Init();
  MX_ADC3_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  MX_TIM2_Init();
  MX_USB_OTG_FS_USB_Init();
  MX_TIM5_Init();
  /* USER CODE BEGIN 2 */
  Regen_Resistor_Init();                ///somebp 2024.02.02
  //System_Wakeup();                      //for Wake-up from Sleep mode     //not necessary

  DAC1_Start();
  DAC2_Start();

  ADC_Start_DMA();    // 덜 중요
  //  ADC_SWStart();                      //Start Trigger

  ADC1_InjectedStart_IT();    // 중요 -> 전류 제어 관련 (전류 센싱, DC전압,위치), 3상 전류 하이 로우 6개 + 위치 2*2개 + DC전압 + 여분1개
  ADC2_InjectedStart_IT();    // 주석 처리하는 게 맞아 보임!!!
  ADC3_InjectedStart_IT();    // 1,2와 달리 3은 인젝티트 모드가 아니라 폴링으로 도는 (덜 중요한) 채널이 같이 있어서, DMA로 도는... (이해 어려움)

//  Init_ADC_IDC();

  //  HAL_TIM_Encoder_Start_IT(&htim4, TIM_CHANNEL_ALL);
  //  HAL_TIM_Encoder_Start_IT(&htim2, TIM_CHANNEL_ALL);
  HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);
  HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_ALL);

  //  TIM1_PWM_Start_IT(TIM_CHANNEL_1);         //include TIM1_Start()
  //  TIM1_PWM_Start_IT(TIM_CHANNEL_2);         //
  //  TIM1_PWM_Start_IT(TIM_CHANNEL_3);         //
  //  TIM1_PWMN_Start_IT(TIM_CHANNEL_1);
  //  TIM1_PWMN_Start_IT(TIM_CHANNEL_2);
  //  TIM1_PWMN_Start_IT(TIM_CHANNEL_3);

  TIM1_PWM_Start_IT(TIM_CHANNEL_4);
  TIM1_PWMN_Start_IT(TIM_CHANNEL_4);
  //  TIM1_Enable_IT(TIM_IT_UPDATE);
  TIM1_Stop();

  //  TIM8_PWM_Start_IT(TIM_CHANNEL_1);         //include TIM8_Start()
  //  TIM8_PWM_Start_IT(TIM_CHANNEL_2);         //
  //  TIM8_PWM_Start_IT(TIM_CHANNEL_3);         //
  //  TIM8_PWMN_Start_IT(TIM_CHANNEL_1);
  //  TIM8_PWMN_Start_IT(TIM_CHANNEL_2);
  //  TIM8_PWMN_Start_IT(TIM_CHANNEL_3);
  //  TIM8_Enable_IT(TIM_IT_UPDATE);
  TIM8_Stop();

  HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_1);

  HAL_TIM_PWM_Start(&htim5,TIM_CHANNEL_1);
  HAL_NVIC_DisableIRQ(DMA2_Stream0_IRQn);

//  ※※ 아래 구문이 시작되면서 핵심 수행 주기가 돌아감 !! - HAL_ADCEx_InjectedConvCpltCallback
  TIM1_Start();     // 완전 동시에 맞춘 상태는 아니고 거의 동시
  TIM8_Start();
  Motor1Ctrl_PwmStart();
  Motor2Ctrl_PwmStart();
//  여기까지 지나면 모터제어 준비가 완전히 준비 완료!!! (ADC 오프셋 캘리브레이션


  Flash_Init();                               //Backup or Restore
//  BLE_Rename(BLE_NAME);                       //MUST run only ONE time.
  LED_Send_All(60, 0,0,0, 0,0,0);             //Addressable LED turn OFF
  Delay_msec(110);                             //somebp 2024.02.08

//  LED_Send_All(60, 26, 13, 8, 10, 10, 10);   // 부팅 시 EncInit 단계를 시각화
//  Delay_msec(110);

  Initialize_WESPION();
  Delay_msec(100);

  MotorInitStart = 1;   //  이제 EncInit 시작!

  if(DebugingPrintActive == 0) {
    DebugingPrintActive = 1;
    Debug_UART3_printf("\r\n---------- ---------- ----------\r\nRoomFit On!\r\n");
    Debug_UART3_printf("FW v%d.%d.%d (%04d.%02d.%02d)\r\n",WespionVer.VerMajer,WespionVer.VerMiner,WespionVer.VerSub,WespionVer.VerYear,WespionVer.VerMonth,WespionVer.VerDate);///somebp 2024.02.08
    DebugingPrintActive = 0;
  }
//  LED_Welcome();    //  이걸 Init_AngleElec 성공 직후로 옮기는 게 적절!!

  //  Task_Start_1ms(Task1ms);
  ISR_Profile_Init();                    //  [v1.0.2] DWT Cycle Counter 활성화
  Task_Start_5ms(ISR_DeferredNotify);   //  [v1.0.2] ISR 지연 알림 처리 (UART/BLE 전송)
  //  [v1.0.4] Debug Report는 Task50ms()에서 100ms 주기로 호출 (스케줄러 슬롯 충돌 방지)
  Task_Start_50ms(Task50ms);
  Task_Start_100ms(Task100ms);  //  LED_Dispaly_Level
  Task_Start_60s(Report_Vdc);   //  Voltage Report - Periodic
  Task_Start_100ms(LED_Controller);
//  Task_Start_10s(Task10s);

  // 250703) 이제 이건 실제 원인 행위 발생 시점에 건드리자
//  switch(Drive_Status) {
//    case RunGym:
//      Debug_DriveMotor = Drv_BothMotor;
//      break;
//    case Calibration:
//      //  일단 개별 구동할 케이스는 없으니 (모터 제어 자체를 안 할 이유는 x)
//      Debug_DriveMotor = Drv_BothMotor;
//      break;
//    case Debug:
//      Debug_DriveMotor = Drv_NoMotor;
//      break;
//  }

//  Init_ADC_I_CHG();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

  int32_t LED_Period = 500;    //  [msec]
  int8_t NumSequence = 5;
//  int8_t cnt_WelcomeLED=0;

  while(1) {
    //  Dac를 통해 수행 주기 체크 (Dac 세팅에 소요 시간을 최소화하기 위해 레지스터 직접 설정 방식 적용 by ChatGPT)
//    static uint32_t dac_value = 0;
//    dac_value = (dac_value == 0) ? 2048 : 0;
//    // DAC1 채널 1 (PA4) 값 설정 - 레지스터 직접 조작
//    DAC->DHR12R1 = dac_value;
//    DAC->SWTRIGR |= DAC_SWTRIGR_SWTRIG1;  // 소프트웨어 트리거 (출력 반영)


//    Regen_Resistor_Control();           ///somebp 2024.02.02
    Regen_Resistor_Control_HSW();     // 수행시간 부족 유발로 수행 위치 이동 테스트 중 -> 스케쥴러 시도 (2/27)
//    Derating_Control(L);
//    Derating_Control(R);
    Protocol_Receive_Task_Uart3();    // BLE Protocol is more important than being in this location.... (24.02.09)

    Check_BLE_Status();

    Time = Get_Time();

//    if(First_Init_ADC_IDC == 0 && Time > 500) {
//      Init_ADC_IDC();
//      First_Init_ADC_IDC++;
//    }

    /* 부팅 후 영점 조정이랑 부팅 후 첫 캘리를 통합하는 게 더 완벽하겠다 (너무 많이 풀려있으면 웰컴라이트가 먼저 끝나서 당길 수 있음)
     * 아 근데 그럼 어차피 감기고 있는 걸 인지할 수 있긴 함!! 일단 나중에 하자.. */
    /* 부팅 후 최초 영점 조정 - 강제 캘리 스킵할 경우 대비 */\
    //  LED_Welcome 마지막에 InitialPosCali를 1로 갱신하고 있음
    if(Active_ForcedCalib == 0 && InitialPosCali == 1 &&  Drive_Status == RunGym
        && Motor1_Ang.RpmFil < 5.0f && Motor2_Ang.RpmFil < 5.0f) {
      PositionCalibrate(LR);
      InitialPosCali++;
    }
    /* (통합 전)엔코더 초기화, 강제 캘리(스킵) 완료 후 메세지 & 웰컴 라이트 */
    if(WP_ForcedCali.Flag == Done && cnt_LED_Welcome ==0 && status_LED_Welcome == 0) {
      if(DebugingPrintActive == 0) {
        DebugingPrintActive = 1;
        Debug_UART3_printf("\r\n - Motor Ready, Let's move out! \r\n");
        DebugingPrintActive = 0;
      }
      LED_Welcome();
    }


    /* 유저 요청에 의한 강제 캘리 */
    if(ReStart_ForcedCalib){
      cnt_LED_Calib = 0;
      cnt_LED_Calib_Err = 0;
      cnt_LED_Welcome = 0;

      Active_ForcedCalib = 1;
      WP_ForcedCali.Flag = NotDone;
      WP_ForcedCali.Status[L] = WP_ForcedCali.Status[R] = 0;
      WP_ForcedCali.Step[L] = WP_ForcedCali.Step[R] = 0;
      Drive_Status = Calibration;

      ReStart_ForcedCalib = 0;
    }

    /**/
//    if(debug_LED_Color) {
//      LED_On_ALL(debug_LED_R,debug_LED_G,debug_LED_B);
//      Delay_msec(110)
//    }

    check_While++;

//    if(cnt_WelcomeLED == 0){
//      switch(Drive_Status){
//        case RunGym:
//          LED_Welcome();
//          cnt_WelcomeLED++;
//          break;
//        case Calibration:
//          LED_On_ALL(12, 25, 0, 20);
//          break;
//        case EncInit:
//          LED_On_ALL(26, 13, 8, 20);
//          break;
//
//      }
//    }

    I_CHG = Get_I_CHG();

    //    MaxDa1 = 2047.0f/ 3300.0f;  // 1650.0f;
    //    MaxDa2 = 2047.0f/ 3300.0f;  // 1650.0f;
    //    Dac1 = (int32_t) WP_Gym.Speed[L] * 2047.0f / 330.0f + 2047;
    //    Dac2 = (int32_t) WP_Gym.Speed[R] * 2047.0f / 330.0f + 2047;
//    DAC1_SetValue(Dac1);
//    DAC2_SetValue(Dac2);
    //    check_Dac++;

    //other Tasks
    Inverter_Comm();      // (25.05.05) 주요하지 않은 ADC 변수들 일괄로 불러오고 후처리 하는 코드로 보임
    //    WESPION_MotorAddon();   // 모터제어 코드에 들어갔음

    //////////////////////////////////////////////////////////////////////
//    if(0)
//    {                   // NTC TEST
//      static uint32_t old_time = 0;
//      uint32_t new_time=Get_Time();
//      if(new_time - old_time > 1000) {
//        old_time = new_time;
//        UART3_printf("[%d] %d, NTC:%s'C\t",   0, ADC_Buffer[2], Float2String(Get_Temperature(0), 3));
//        UART3_printf("[%d] %d, NTC:%s'C\r\n", 1, ADC_Buffer[3], Float2String(Get_Temperature(1), 3));
//      }
//    }
    //////////////////////////////////////////////////////////////////////

    // 디버깅용 - 영점 캘리브레이션
    if(Debug_Calib != 0) {
      switch (Debug_Calib) {
        case 1:
          PositionCalibrate(L);
          Debug_Calib=0;
          break;
        case 2:
          PositionCalibrate(R);
          Debug_Calib=0;
          break;
        case 3:
          PositionCalibrate(LR);
          Debug_Calib=0;
          break;
      }
    }

//    AT Command for RMBT 양산 버전 (4/15)
//    이걸 동작할 땐 모터제어도 안 하니까 뒤로 위치 변경 (250702)
//    switch (Debug_ATCommand){
//      case 0:
//        break;
//      case 1:
//        UART_printf(&huart3, "AT+NAMERoomFit20415");
//        Delay_msec(250);
//        Debug_ATCommand = 10;
//        break;
//      case 12:
//        UART_printf(&huart3, "AT?MACADDR");
//        Delay_msec(250);
//        ATmacaddr[0] = UART_Getc_NoClear(&huart3,8);    // 리턴이 12자리이므로 9, 10, 11, 12번 째를 가져옴
//        ATmacaddr[1] = UART_Getc_NoClear(&huart3,9);
//        ATmacaddr[2] = UART_Getc_NoClear(&huart3,10);
//        ATmacaddr[3] = UART_Getc_NoClear(&huart3,11);
//        Delay_msec(350);
//        UART_printf(&huart3, "AT+NAME%s%s", ATname, ATmacaddr);
//        Delay_msec(250);
//        Debug_ATCommand = 10;
//        break;
//      case 2:
//        UART_printf(&huart3, "AT?BAUDRATE");
//        Delay_msec(250);
//        Debug_ATCommand = 20;
//        break;
//      case 22:
//        UART_printf(&huart3, "AT+BAUDRATE115200");
//        Delay_msec(250);
//        Debug_ATCommand = 20;
//        break;
//      case 9:
//        UART_printf(&huart3, "AT+Reset");
//        Delay_msec(250);
//        Debug_ATCommand = 99;
//        break;
//      case 91:
//        UART_printf(&huart3, "AT?NAME");
//        Delay_msec(250);
//        Debug_ATCommand = 99;
//        break;
//      case 92:
//        UART_printf(&huart3, "AT?MACADDR");
//        Delay_msec(250);
//        ATmacaddr[0] = UART_Getc_NoClear(&huart3,8);    // 12자리이므로 9, 10, 11, 12번 째를 가져옴
//        ATmacaddr[1] = UART_Getc_NoClear(&huart3,9);
//        ATmacaddr[2] = UART_Getc_NoClear(&huart3,10);
//        ATmacaddr[3] = UART_Getc_NoClear(&huart3,11);
//        Debug_ATCommand = 99;
//        break;
//      case 93:
//        UART_printf(&huart3, "AT?BAUDRATE");
//        Delay_msec(250);
//        Debug_ATCommand = 99;
//        break;
//    }

//    LED는 진짜 제일 필요 없으니 맨 마지막. 배포 시엔 아예 끄는 게 지구에 도움될 지도 (250702)
    if(Time % LED_Period == 0) {
      digitalWrite(56, 1);
      digitalWrite(57, 1);
      digitalWrite(87, 1);
      //      digitalWrite(88, 1);
      //      digitalWrite(89, 1);
      //      digitalWrite(90, 1);
    } else if (Time % LED_Period == LED_Period/NumSequence*1) {
      //      digitalWrite(56, 0);
      //      digitalWrite(88, 0);
    } else if (Time % LED_Period == LED_Period/NumSequence*2) {
      digitalWrite(57, 0);
      digitalWrite(56, 0);
      digitalWrite(87, 0);
      //      digitalWrite(89, 0);
    } else if (Time % LED_Period == LED_Period/NumSequence*3) {
      //      digitalWrite(87, 0);
      //      digitalWrite(90, 0);
    }
  }
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  /* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
   */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
   * in the RCC_OscInitTypeDef structure.
   */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 6;
  RCC_OscInitStruct.PLL.PLLN = 180;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Activate the Over-Drive mode
   */
  if (HAL_PWREx_EnableOverDrive() != 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_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
 * @brief Peripherals Common Clock Configuration
 * @retval None
 */
void PeriphCommonClock_Config(void)
{
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

  /** Initializes the peripherals clock
   */
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_TIM;
  PeriphClkInitStruct.TIMPresSelection = RCC_TIMPRES_ACTIVATED;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* 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 */
