/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    stm32g0xx_it.c
  * @brief   Interrupt Service Routines.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32g0xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "modbus.h"
#include "SEGGER_RTT.h"
#include "dac.h"
#include "log.h"
#include "precharge.h"

/* USER CODE END Includes */

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

/* USER CODE END TD */

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

#define TAG "ISR " 

/* USER CODE END PD */

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

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

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

/* USER CODE END 0 */

/* External variables --------------------------------------------------------*/
extern DMA_HandleTypeDef hdma_adc1;
extern ADC_HandleTypeDef hadc1;
extern DAC_HandleTypeDef hdac1;
extern TIM_HandleTypeDef htim6;
extern TIM_HandleTypeDef htim7;
extern TIM_HandleTypeDef htim14;
extern TIM_HandleTypeDef htim15;
extern TIM_HandleTypeDef htim16;
extern TIM_HandleTypeDef htim17;
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN EV */

extern uint16_t ADC_values[ADC_CHANNELS];
extern uint16_t rawMOSFETsVoltageDrop;
extern int32_t rawContactVoltageDropPlus;
extern int32_t rawContactVoltageDropMinus;
extern int command_parser_is_enabled;
extern void DoNothing(void);
extern void OpenBothMOSFETSVeryFast(void);
extern void (*MOSFETS_Management)(void);										// function pointer
extern void	(*ExternalGreenLED_Management)(void);
extern sys_data_t sys_data;
extern void ADC_Open_Both_MOSFETs(void);
extern void ADC_Close_Both_MOSFETs(void);
extern void TurnExternalGreenLEDOff(void);
extern void TurnExternalGreenLEDOn(void);
extern void	(*AUTO_Mode)(uint32_t, int);	// Function pointer that contains function that is executed when gSwitch is in AUTO mode (depends on DIP switches)
extern void EnterPowerSavingMode(void);
extern void ExternalGreenLEDShortBlinking(void);
extern int overcurrent_shutdown_is_active;
extern int overload_shutdown_is_active;
extern uint32_t overcurrent_shutdown_time;
//extern uint32_t overload_shutdown_time;
extern void (*InrushCurrentManagement)(void);
extern int low_bat_shutdown_is_active;

//extern uint16_t i_samples[I_RMS_SAMPLES_COUNT];
//extern uint16_t d_samples[I_RMS_SAMPLES_COUNT];
//extern uint16_t u_samples[I_RMS_SAMPLES_COUNT];
//extern volatile int32_t i_samples_counter;
extern int statDataChanged;
extern volatile uint32_t maxIntegral;

/* USER CODE END EV */

/******************************************************************************/
/*           Cortex-M0+ Processor Interruption and Exception Handlers          */
/******************************************************************************/
/**
  * @brief This function handles Non maskable interrupt.
  */
void NMI_Handler(void)
{
  /* USER CODE BEGIN NonMaskableInt_IRQn 0 */

  /* USER CODE END NonMaskableInt_IRQn 0 */
  HAL_RCC_NMI_IRQHandler();
  /* USER CODE BEGIN NonMaskableInt_IRQn 1 */

  while (1)
  {
	//OpenBothMOSFETS();
    HAL_GPIO_TogglePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin);
	SEGGER_RTT_WriteString(0, "NMI ERROR!!!\n");
  }

  /* USER CODE END NonMaskableInt_IRQn 1 */
}

/**
  * @brief This function handles Hard fault interrupt.
  */
void HardFault_Handler(void)
{
  /* USER CODE BEGIN HardFault_IRQn 0 */
  SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_BRIGHT_RED);
  SEGGER_RTT_WriteString(0, "Hardfault ERROR!!!\n");
  /* USER CODE END HardFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_HardFault_IRQn 0 */
    HAL_GPIO_TogglePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin);
	//OpenBothMOSFETS();
	
    /* USER CODE END W1_HardFault_IRQn 0 */
  }
}

/**
  * @brief This function handles System service call via SWI instruction.
  */
void SVC_Handler(void)
{
  /* USER CODE BEGIN SVC_IRQn 0 */

  /* USER CODE END SVC_IRQn 0 */
  /* USER CODE BEGIN SVC_IRQn 1 */

  /* USER CODE END SVC_IRQn 1 */
}

/**
  * @brief This function handles Pendable request for system service.
  */
void PendSV_Handler(void)
{
  /* USER CODE BEGIN PendSV_IRQn 0 */

  /* USER CODE END PendSV_IRQn 0 */
  /* USER CODE BEGIN PendSV_IRQn 1 */

  /* USER CODE END PendSV_IRQn 1 */
}

/**
  * @brief This function handles System tick timer.
  */
#ifdef USE_RAM_FUNC
__RAM_FUNC void SysTick_Handler(void)
#else
void SysTick_Handler(void)
#endif
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
  //LED_ERROR_GPIO_Port->BSRR = LED_ERROR_Pin;
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
  //LED_ERROR_GPIO_Port->BRR = LED_ERROR_Pin;
  /* USER CODE END SysTick_IRQn 1 */
}

/******************************************************************************/
/* STM32G0xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32g0xx.s).                    */
/******************************************************************************/

/**
  * @brief This function handles DMA1 channel 1 interrupt.
  */
#ifdef USE_RAM_FUNC
__RAM_FUNC void DMA1_Channel1_IRQHandler(void)
#else
void DMA1_Channel1_IRQHandler(void)
#endif
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
  TP2_GPIO_Port->BSRR = TP2_Pin;

  static uint32_t current_integral = 0;

  rawMOSFETsVoltageDrop = ADC_values[MOSFETS_VDROP_CHANNEL];

  /*if (ADC_values[U_BAT_CHANNEL] < ADC_BAT_CRITICAL_VOLTAGE)
  {
	  MOSFETS_Management = &OpenBothMOSFETSVeryFast;
	  if (low_bat_shutdown_is_active == 0)
	  {
			sys_data.s.ubsenseb_voltage = 0;
			low_bat_shutdown_is_active = 1;
			sys_data.s.device_status |= (1 << LOWBAT_ERROR);
			sys_data.s.lowbat_error_cnt++;
			statDataChanged = 1;
	  }
  }*/

  MOSFETS_Management();

  rawContactVoltageDropPlus = ADC_values[I_PLUS_CHANNEL];	  // Charge current sensor raw value
  rawContactVoltageDropMinus = ADC_values[I_MINUS_CHANNEL];	  // Discharge current sensor raw value

  DMA1->IFCR |= DMA_FLAG_TC1;
  
  uint32_t current_adc_value = (rawContactVoltageDropPlus >= rawContactVoltageDropMinus)? rawContactVoltageDropPlus: rawContactVoltageDropMinus;

  if (current_adc_value >= sys_data.s.copper_v_drop_adc_limit)
  {
	  current_integral += current_adc_value;
	  if (current_integral > maxIntegral)	  // maxIntegral updated in main loop
	  {
		  InrushCurrentManagement();
		  current_integral = 0;
	  }
  }
  else current_integral = 0;

  TP2_GPIO_Port->BRR = TP2_Pin;

  return;
  /* USER CODE END DMA1_Channel1_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_adc1);
  /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
  /* USER CODE END DMA1_Channel1_IRQn 1 */
}

/**
  * @brief This function handles ADC1, COMP1 and COMP2 interrupts (COMP interrupts through EXTI lines 17 and 18).
  */
#ifdef USE_RAM_FUNC
__RAM_FUNC void ADC1_COMP_IRQHandler(void)
#else
void ADC1_COMP_IRQHandler(void)
#endif
{
  /* USER CODE BEGIN ADC1_COMP_IRQn 0 */
  //LED_STATE_GPIO_Port->BSRR = LED_STATE_Pin;
  //  DO NOT BREAKPOINT THIS !!! MOSFETs DIES!!!

  // We open both MOSFETs arrays no matter which way overcurrent happened
  OpenBothMOSFETSVeryFast();
  HAL_NVIC_DisableIRQ(ADC1_COMP_IRQn);
  //__HAL_ADC_CLEAR_FLAG(&hadc1, (ADC_FLAG_AWD3 | ADC_FLAG_AWD2));
  MOSFETS_Management = &DoNothing;
  if (overload_shutdown_is_active == 0)
  {
	overcurrent_shutdown_is_active = 1;
	overcurrent_shutdown_time = uwTick;
	sys_data.s.overcurrent_error_cnt++;
	statDataChanged = 1;
  }
  //LED_STATE_GPIO_Port->BRR = LED_STATE_Pin;
  return;
  /* USER CODE END ADC1_COMP_IRQn 0 */
  HAL_ADC_IRQHandler(&hadc1);
  /* USER CODE BEGIN ADC1_COMP_IRQn 1 */
  /* USER CODE END ADC1_COMP_IRQn 1 */
}

/**
  * @brief This function handles TIM6, DAC1 and LPTIM1 interrupts (LPTIM1 interrupt through EXTI line 29).
  */
void TIM6_DAC_LPTIM1_IRQHandler(void)
{
  /* USER CODE BEGIN TIM6_DAC_LPTIM1_IRQn 0 */

  HAL_TIM_IRQHandler(&htim6);
  // We dont't use DAC ISR
  return;

  /* USER CODE END TIM6_DAC_LPTIM1_IRQn 0 */
  HAL_TIM_IRQHandler(&htim6);
  HAL_DAC_IRQHandler(&hdac1);
  /* USER CODE BEGIN TIM6_DAC_LPTIM1_IRQn 1 */

  /* USER CODE END TIM6_DAC_LPTIM1_IRQn 1 */
}

/**
  * @brief This function handles TIM7 and LPTIM2 interrupts (LPTIM2 interrupt through EXTI line 30).
  */
void TIM7_LPTIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM7_LPTIM2_IRQn 0 */

  /* USER CODE END TIM7_LPTIM2_IRQn 0 */
  HAL_TIM_IRQHandler(&htim7);
  /* USER CODE BEGIN TIM7_LPTIM2_IRQn 1 */

  /* USER CODE END TIM7_LPTIM2_IRQn 1 */
}

/**
  * @brief This function handles TIM14 global interrupt.
  */
void TIM14_IRQHandler(void)
{
  /* USER CODE BEGIN TIM14_IRQn 0 */

  /* USER CODE END TIM14_IRQn 0 */
  HAL_TIM_IRQHandler(&htim14);
  /* USER CODE BEGIN TIM14_IRQn 1 */

  /* USER CODE END TIM14_IRQn 1 */
}

/**
  * @brief This function handles TIM15 global interrupt.
  */
void TIM15_IRQHandler(void)
{
  /* USER CODE BEGIN TIM15_IRQn 0 */

  /* USER CODE END TIM15_IRQn 0 */
  HAL_TIM_IRQHandler(&htim15);
  /* USER CODE BEGIN TIM15_IRQn 1 */

  /* USER CODE END TIM15_IRQn 1 */
}

/**
  * @brief This function handles TIM16 global interrupt.
  */
void TIM16_IRQHandler(void)
{
  /* USER CODE BEGIN TIM16_IRQn 0 */

  /* USER CODE END TIM16_IRQn 0 */
  HAL_TIM_IRQHandler(&htim16);
  /* USER CODE BEGIN TIM16_IRQn 1 */

  /* USER CODE END TIM16_IRQn 1 */
}

/**
  * @brief This function handles TIM17 global interrupt.
  */
void TIM17_IRQHandler(void)
{
  /* USER CODE BEGIN TIM17_IRQn 0 */

  /* USER CODE END TIM17_IRQn 0 */
  HAL_TIM_IRQHandler(&htim17);
  /* USER CODE BEGIN TIM17_IRQn 1 */

  /* USER CODE END TIM17_IRQn 1 */
}

/**
  * @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25.
  */
#ifdef USE_RAM_FUNC
__RAM_FUNC void USART1_IRQHandler(void)
#else
void USART1_IRQHandler(void)
#endif
{
  /* USER CODE BEGIN USART1_IRQn 0 */
  //LED_ERROR_GPIO_Port->BSRR = LED_ERROR_Pin;

  MODBUS_UART_IRQHandler(&huart1);

  //LED_ERROR_GPIO_Port->BRR = LED_ERROR_Pin;
  return;

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

/* USER CODE BEGIN 1 */

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef * htim)
{
	// We don't have periodic timer interrupts, so we can disable any timer, which generated interrupt
    HAL_TIM_Base_Stop_IT(htim);

    if (htim->Instance == TIM6)
    {   // This timer is used to start MOSFETs ON mode only after 250ms delay after turn on of VBOOST voltage
		sys_data.s.user_button_mode = SWITCH_ON;

#ifdef INVERTER_CAP_PRECHARGE
		SetReturnFunction(&ADC_Close_Both_MOSFETs);
		MOSFETS_Management = &PreChargeStage;
#else
		MOSFETS_Management = &ADC_Close_Both_MOSFETs;
#endif
		//MOSFETS_Management = &ADC_Close_Both_MOSFETs;
		sys_data.s.relay_status = RELAY_IS_CLOSED;
		ExternalGreenLED_Management = &TurnExternalGreenLEDOn;
    }
    else if (htim->Instance == VBOOST_ON_TIMER.Instance)
    {   // This timer is used to start MOSFETs regulation only after 250ms delay after VBOOST voltage activation in AUTO mode
		sys_data.s.user_button_mode = SWITCH_AUTO;
		AUTO_Mode(0, 1);  // Reinitializing AUTO mode
    }
    else if (htim->Instance == VBOOST_OFF_TIMER.Instance)
    {
        // This timer is used to turn off VBOOST voltage after 100ms after entering into OFF mode
        //HAL_GPIO_WritePin(DISABLE_VBOOST_GPIO_Port, DISABLE_VBOOST_Pin, VBOOST_DISABLE);
    }
	else if (htim->Instance == TIM15)
	{
#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
		EnableShortCutDetection();
		HAL_TIM_Base_Stop_IT(htim);
#endif
	}
    else if (htim->Instance == TIM16)
    {
#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
		DisableShortCutDetection();
#endif
        // This timer is used to turn off switch after 60sec after entering into ON mode
        sys_data.s.user_button_mode = SWITCH_OFF;
        MOSFETS_Management = &ADC_Open_Both_MOSFETs;
		sys_data.s.relay_status = RELAY_IS_OPENED;
        ExternalGreenLED_Management = &TurnExternalGreenLEDOff;

		// After 100ms we turn off VBOOST voltage for power saving
		HAL_TIM_Base_Stop_IT(&VBOOST_OFF_TIMER);
		__HAL_TIM_CLEAR_FLAG(&VBOOST_OFF_TIMER, TIM_FLAG_UPDATE);
		__HAL_TIM_SET_COUNTER(&VBOOST_OFF_TIMER, 0);
		HAL_TIM_Base_Start_IT(&VBOOST_OFF_TIMER);
    }
    else if (htim->Instance == TIM17)
    {
        // This timer is used to stop parsing Modbus commands for 10sec after illegal command is recieved
        command_parser_is_enabled = 1;
    }
}

//------------------------------------------------------------------------------

/* USER CODE END 1 */
