/* 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"
#include "adc.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "iwdg.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "button.h"
#include "buzzer.h"
#include "relais.h"
#include "leds.h"
#include "fan.h"
#include "chip_temperature.h"
#include "modeswitch.h"
#include "mode_mainswitch.h"
#include "mode_secondaryprotection.h"
#include "mode_secondaryprotection_plus.h"
#include "mode_lvp.h"
#include "mode_ovp.h"
#include "mode_lvp_ovp.h"
#include "voltage_meas.h"
#include "modbus.h"
#include "sysdata.h"
#include "eeprom.h"
/* USER CODE END Includes */

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

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
int oldTimeMSTick;
int oldTimeSeconds;
int msCounter;
int silentmode = 0;
/* USER CODE END PD */

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

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint32_t bootLoaderMark __attribute__((section(".no_init")));
static volatile uint32_t adcData[5];
modbus_t modbusData __attribute__((section(".RAM1")));
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);

/* USER CODE BEGIN PFP */
void JumpToBootloader(void);
/* 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 */
  if (bootLoaderMark == GOTO_SYSTEM_BOOTLOADER_MARK)
  {
	  bootLoaderMark = 0;
	  JumpToBootloader();
  }

  if (FLASH->OPTR & FLASH_OPTR_nBOOT_SEL)
  {
	  printf("setze option byte\r\n");

	  HAL_FLASH_Unlock();
	  FLASH_WaitForLastOperation(1000);
	  HAL_FLASH_OB_Unlock();
	  FLASH_WaitForLastOperation(1000);

	  FLASH->OPTR &= ~FLASH_OPTR_nBOOT_SEL;

	  FLASH_WaitForLastOperation(1000);

	  FLASH->CR |= FLASH_CR_OPTSTRT;

	  FLASH_WaitForLastOperation(1000);

	  HAL_FLASH_OB_Launch();
  }
  
  unsigned pwm = 0U;

  


  /* 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_DMA_Init();
  MX_ADC1_Init();
  MX_TIM16_Init();
  MX_TIM17_Init();
  MX_IWDG_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  

  //Eprom test
  if (EEPROM_ReadFirstStart() == 0xff) 
  {
#ifdef DEBUG
	printf("Erststart erkannt, schreibe Werkseinstellung\r\n");
#endif
	EEPROM_WriteDefaults();
  }
  else if(EEPROM_ReadFirstStart() != FIRST_START_ID) 
  {
#ifdef DEBUG
	printf("Neue Version Parameter erkannt, schreibe Werkseinstellung\r\n");
#endif
	EEPROM_WriteDefaults();
  }
  else
  {
#ifdef DEBUG
	printf("Konfig vorhanden\r\n");
#endif
  }

  EEPROM_ReadDeviceParameter();
  //
  
  SYS_DATA_Init();
#ifdef DEBUG
  printf("debug io test...ok\r\n");
#endif
  mbInit(&modbusData, sys_data.s.parameter.baudrate, sys_data.s.parameter.parityMode, sys_data.s.parameter.stopBit, &huart1);

  HAL_GPIO_WritePin(GPIO_OUTPUT_BUZZER_GPIO_Port, GPIO_OUTPUT_BUZZER_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIO_OUTPUT_LED_ERROR_GPIO_Port, GPIO_OUTPUT_LED_ERROR_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIO_OUTPUT_LED_ON_GPIO_Port, GPIO_OUTPUT_LED_ON_Pin, GPIO_PIN_SET);
  HAL_Delay(500);
  HAL_GPIO_WritePin(GPIO_OUTPUT_BUZZER_GPIO_Port, GPIO_OUTPUT_BUZZER_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIO_OUTPUT_LED_ERROR_GPIO_Port, GPIO_OUTPUT_LED_ERROR_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIO_OUTPUT_LED_ON_GPIO_Port, GPIO_OUTPUT_LED_ON_Pin, GPIO_PIN_RESET);

  //Spannungsregler für Mosfet ein (Relais Schaltstufe)
  HAL_GPIO_WritePin(GPIO_OUTPUT_10V_EN_GPIO_Port, GPIO_OUTPUT_10V_EN_Pin, GPIO_PIN_SET);

    //--- RELAIS ZURÜCKSETZEN, damit es definitiv aus ist ---
  //Sicherstellen das nicht noch die Set Spule aktiv geschaltet ist
  HAL_GPIO_WritePin(GPIO_OUTPUT_RELAIS_SET_GPIO_Port, GPIO_OUTPUT_RELAIS_SET_Pin, GPIO_PIN_RESET);

  //Puls starten
  HAL_GPIO_WritePin(GPIO_OUTPUT_RELAIS_RESET_GPIO_Port, GPIO_OUTPUT_RELAIS_RESET_Pin, GPIO_PIN_SET);
  HAL_Delay(50);
  HAL_GPIO_WritePin(GPIO_OUTPUT_RELAIS_RESET_GPIO_Port, GPIO_OUTPUT_RELAIS_RESET_Pin, GPIO_PIN_RESET);
  //--- RELAIS ZURÜCKSETZEN ENDE ----

  MODESWITCH_ReadMode();
  sys_data.s.parameter.operatingMode = MODESWITCH_GetMode();

  CHIP_TEMPERATURE_Calibration(/*&sys_data*/);
  HAL_ADCEx_Calibration_Start(&hadc1);
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcData, 5);


	
  extern uint32_t frequency, ic_overflows;
  ic_overflows = 0U;
  __HAL_TIM_SetCounter(&htim16, 0U);

  HAL_TIM_Base_Start_IT(&htim16);
  HAL_TIM_IC_Start_IT(&htim16, TIM_CHANNEL_1);
  int oldcaptureValue=0;





  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
	HAL_IWDG_Refresh(&hiwdg);


    if (mbGetFrameComplete(&modbusData) == true)
    {
      if (mbSlaveCheckModbusRtuQuery(&modbusData) == RESPOND_TO_QUERY)
      {
          if (silentmode == 0)
          {
            mbSlaveProcessRtuQuery(&modbusData);
          }
      }
      else
      {
        huart1.RxState = HAL_UART_STATE_BUSY_RX;
      }
    }




	if (oldTimeMSTick != HAL_GetTick())
    {
      BUTTON_Exec();
      BUZZER_Exec();
      RELAIS_Exec(adcData[0]);
      LEDS_Exec();
	  VOLTAGE_MEAS_Exec(adcData[1],adcData[2]);
  
      oldTimeMSTick = HAL_GetTick();
	  msCounter++;
    }


	//Sekunden tick
	if (msCounter >= 999)
	{
	  msCounter = 0;
      CHIP_TEMPERATURE_Exec(adcData[4]);
	  sys_data.s.values.chipTemp = CHIP_TEMPERATURE_GetTemp();

	  if ( sys_data.s.values.chipTemp > 50)
	  {  
		  pwm++;
		  if (pwm > 100U) pwm = 100U;	
		  
	  }
	  if (sys_data.s.values.chipTemp < 50)
	  {
		if (pwm > 0) pwm--;
	  }
	 
	  FAN_SetSpeed(pwm);

	  sys_data.s.values.voltage_input = VOLTAGE_MEAS_GetUin();
	  sys_data.s.values.voltage_output = VOLTAGE_MEAS_GetUout();
	  sys_data.s.values.voltage_relais = (int32_t) sys_data.s.values.voltage_input - (int32_t) sys_data.s.values.voltage_output ;
	  uint32_t rpm;
	  rpm = frequency / 2;
	  rpm = rpm * 60;
	  sys_data.s.values.fan_rpm = rpm;
	  sys_data.s.values.fan_pwm = pwm;
	  sys_data.s.values.lvp_state = HAL_GPIO_ReadPin(GPIO_INPUT_LVP_GPIO_Port, GPIO_INPUT_LVP_Pin);
	  sys_data.s.values.ovp_state = HAL_GPIO_ReadPin(GPIO_INPUT_OVP_GPIO_Port, GPIO_INPUT_OVP_Pin);
	  if (HAL_GPIO_ReadPin(GPIO_INPUT_FAULT_GPIO_Port, GPIO_INPUT_FAULT_Pin) == GPIO_PIN_RESET)
	  {
		sys_data.s.values.fault_state = 1;
	  }else
	  {
		sys_data.s.values.fault_state = 0;
	  }

	  sys_data.s.values.relais_state = RELAIS_GetState();
	  sys_data.s.values.relaisTemp = RELAIS_GetTemp();




	  
	  
	} //endsecond tick



    switch (MODESWITCH_GetMode())
    {
      case MODE_MAINSWITCH: //0
        MODE_MAINSWITCH_Exec();
      break;

      case MODE_MAINSWITCH_SECONDARYPROTECTION://1
        MODE_SECONDARYPROTECTION_Exec(0);
      break;

      case MODE_MAINSWITCH_SECONDARYPROTECTION_PLUS://2
        MODE_SECONDARYPROTECTION_PLUS_Exec(0);
      break;

      case MODE_MAINSWITCH_SECONDARYPROTECTION_AUTO_RETRY://3
        MODE_SECONDARYPROTECTION_Exec(1);
      break;

      case MODE_MAINSWITCH_SECONDARYPROTECTION_PLUS_AUTO_RETRY://4
        MODE_SECONDARYPROTECTION_PLUS_Exec(1);
      break;

	  case MODE_MAINSWITCH_LVP_OVP://5
        MODE_LVP_OVP_Exec();
      break;

      case MODE_MAINSWITCH_LVP://6
        MODE_LVP_Exec();
      break;

      case MODE_MAINSWITCH_OVP://7
        MODE_OVP_Exec();
      break;

      default:
#ifdef DEBUG
		printf("mode not yet implemented\n");
#else
		;
#endif
    }


	if(sys_data.s.parameter.command != 0)
    {
      if  (modbusData.current_query ==  MB_QUERY_NOTHING)
      {
        //printf("CMD = %d\n", sys_data.s.parameter.command);
        switch (sys_data.s.parameter.command )
        {
          case COMMAND_STORE_CONFIG:                          EEPROM_StoreConfig(false);										break;
          case COMMAND_FULL_RESTORE:                          EEPROM_WriteDefaults();											break;
          case COMMAND_FACTORY_RESTORE:                       EEPROM_WriteDefaults();											break;
          case COMMAND_RESTORE_LAST_SAVED_VALUES:             EEPROM_ReadDeviceParameter();										break;
          case COMMAND_STORE_WITH_SERIAL_NUMBER:              EEPROM_StoreConfig(true);											break;	// Seriennummer schreiben
          case COMMAND_RESTART:                               while(1);															break;
      	  case COMMAND_GOTO_SYS_BOOTLOADER:					  bootLoaderMark = GOTO_SYSTEM_BOOTLOADER_MARK;
															  HAL_NVIC_SystemReset();
															  break;
          default:
#ifdef DEBUG
															  printf("UNKNOWN COMMAND\n");
#else
															  ;
#endif
        }
        sys_data.s.parameter.command = 0;
      }
      else
      {
        //printf("wait with execution till modbus communnikation finished\n");
      }
    }

  }
  
  /* USER CODE END 3 */
}

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

  __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_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.HSIDiv = RCC_HSI_DIV4;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void JumpToBootloader (void)
{
	typedef void (SystemBootloader)(void);
#ifdef DEBUG
	printf("Cannot jump in DEBUG mode!\n");
	return;
#endif
	// Disable all interrupts
	__disable_irq();

#ifdef DEINIT_RCC
	// Set the clock to the default state
	HAL_RCC_DeInit();
#endif
#ifdef DEINIT_SYSTICK
	// Disable Systick timer
	SysTick->CTRL = SysTick->LOAD = SysTick->VAL = 0;
#endif
	// Clear Interrupt Enable Register & Interrupt Pending Register
	for (int i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++)
    {
      NVIC->ICER[i] = 0xFFFFFFFF;
      NVIC->ICPR[i] = 0xFFFFFFFF;
    }

	// Set up the jump to boot loader address + 4
	SystemBootloader* sb = (SystemBootloader*) (*((uint32_t *) ((SYSTEM_BOOTLOADER_START_ADDR + 4))));

	// Set the main stack pointer to the bootloader stack
	__set_MSP(*(uint32_t *)SYSTEM_BOOTLOADER_START_ADDR);

	__HAL_RCC_SYSCFG_CLK_ENABLE();
	__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
	//__HAL_RCC_SYSCFG_CLK_DISABLE();

	// Re-enable all interrupts
	__enable_irq();

	// Call the function to jump to boot loader location
	sb();

	// Jump is done successfully
	while (1)
	{
		// Code should never reach this loop
#ifdef DEBUG
		printf("Jump has failed!\n");
#endif
	}
}

/* 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,
     printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
#ifdef DEBUG
	 printf("Wrong parameters value: file %s on line %d\r\n", file, line) ;
#endif
  /* USER CODE END 6 */
  
}
#endif /* USE_FULL_ASSERT */
