/**
  ******************************************************************************
  * File Name          : main.c
  * Description        : Main program body
  ******************************************************************************
  *
  * COPYRIGHT(c) 2016 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */

#include <string.h>
#include <math.h>
#include "led_driver.h"
#include "image_generator.h"
#include "image_filter.h"
#include "remote.h"
#include "globals.h"
#include "wifi.h"
#include "serial.h"
#include "flash.h"

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim6;
TIM_HandleTypeDef htim7;
TIM_HandleTypeDef htim8;
DMA_HandleTypeDef hdma_tim8_ch3;
DMA_HandleTypeDef hdma_tim8_ch1;

UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;
DMA_HandleTypeDef hdma_usart2_tx;
DMA_HandleTypeDef hdma_usart2_rx;

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

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM2_Init(void);
static void MX_TIM3_Init(void);
static void MX_TIM6_Init(void);
static void MX_TIM7_Init(void);
static void MX_TIM8_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);

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

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */


	uint8_t raw_in[RAW_SIZE]; // raw image input to keep pristine
	uint8_t raw_comp[RAW_SIZE]; // intermediate computations
	uint8_t raw_out[RAW_SIZE]; // output to display
	uint8_t rxWifi_raw[RAW_SIZE+4*4];

	uint8_t myColor[3];
	uint16_t t0,t1,t2;
	float frameRate;
	int g_limitFrameRate;
	
#pragma pack(4)
  uint16_t portbmem_flip[NB_DMA_WRITES];
	uint16_t portcmem_flip[NB_DMA_WRITES];

  uint16_t portbmem_flop[NB_DMA_WRITES];
	uint16_t portcmem_flop[NB_DMA_WRITES];

	uint16_t *portbmem_ff[2];
	uint16_t *portcmem_ff[2];
	
	uint16_t *portbmem;
	uint16_t *portcmem;

	float offsetX;
	float goffsetX;
  int ioffsetX;
	
	uint32_t currentMode;
	uint8_t dynamicGenerator;
	uint8_t intensity;	

/*
#define GPIO0_ESP_Pin GPIO_PIN_1
#define GPIO0_ESP_GPIO_Port GPIOA
#define GPIO2_ESP_Pin GPIO_PIN_4
#define GPIO2_ESP_GPIO_Port GPIOA
#define PW_OK_Pin GPIO_PIN_6
#define PW_OK_GPIO_Port GPIOA
#define PS_ON_Pin GPIO_PIN_7
#define PS_ON_GPIO_Port GPIOA
#define RST_ESP_Pin GPIO_PIN_8
#define RST_ESP_GPIO_Port GPIOA
#define GPIO15_ESP_Pin GPIO_PIN_11
#define GPIO15_ESP_GPIO_Port GPIOA
#define EN_ESP_Pin GPIO_PIN_15
#define EN_ESP_GPIO_Port GPIOA
et PC8 exploité par TIM8_CH3


*/


// AUTO MODE 
// On startup or In absence of remote commands for 10 minutes, 

const uint8_t modTable[]={10, 1,22, 6,23, 2,24,11,25, 3,26, 5,21, 4,27,12,28, 1,29,13,30,11,31,14,32,16,33,15,34,17,35,18,36,19,37,20,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53};
uint32_t durationTable[]={ 2,10, 2,10, 2,10, 2,10, 2,10, 2,10,10,10, 2,10, 2,10, 2,10, 2,10, 2,10, 2,10, 2,10, 2,10, 2,10, 2,10, 2,10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};

int findInTable(uint32_t timeSec)
{
	int i;
	for (i=0;i<sizeof(modTable);i++)
	{
		if (timeSec<durationTable[i])
			return i;
	}
	return 10; // sécurité
}
 
void cycler(float time, uint8_t receivedCommand)
{
	static uint8_t initialized = 0;
	static uint8_t neverReceivedACommand = 1;
	static int lastMode;
	static float lastTimereceivedCommand = 0;
	uint32_t dt,modTime;
	static uint32_t modulo;
	int i;
	uint32_t total;
	
	if (!initialized)
	{
		total = 0;
		for (i=0;i<sizeof(modTable);i++)
		{
			total+=durationTable[i]*60; // interprets table expressed in minutes
			durationTable[i] = total; // duration table becomes a startup time table
		}
		modulo = total;
		lastMode = -1;
		initialized = 1;
	}
	
	if (receivedCommand)
	{
		lastTimereceivedCommand = time;
		neverReceivedACommand = 0;
		return;
	}
	
	dt = time-lastTimereceivedCommand;
	
	if ((dt>600)|(neverReceivedACommand))
	{
		// which mode ???
		modTime = ((int) time) % modulo;
//		intensity = 64;

    currentMode = modTable[findInTable(modTime)];	
		
		if (currentMode!=lastMode)
		{
			if (currentMode<IMAGE_MODES_START)
			{
	  switch(currentMode)
		{
			case 6 :
			case 10 : setSpeedRPS(0.025f); break;
			case 11 : setSpeedRPS(0.05f); break;
			default : setSpeedRPS(0); setOffsetX(0); break;
		}		
			}
			else
			{
				setSpeedRPS(0.025f);
			}
		}
		
		if (currentMode!=lastMode) // detects the cycler wants to change mode
		{
			if (lastMode!=7) 
			{
			  currentMode = 7; // one frame black for cleanup, just one frame
			}
		  dynamicGenerator = 1;
		}
		lastMode = currentMode;
	}
	 
}

// Power down and wait for wifi command to wake up
void powerDownListeningWifi(void)
{
	int cmd_id;
	
	powerDownSequenceWifiActive();	
	while(1) // mini main loop that only accepts CMD_OFF commands
	{
		myWait1ms(100);
		while (commandRx(&cmd_id,rxWifi_raw))
		{
			if (cmd_id==CMD_OFF)
			{
				NVIC_SystemReset(); // Received ON. Reboot
			}
		}
		// whatever, if remote asks for stop, do STOP
		#ifdef REMOTE_MANAGER
		remoteManager();
		#endif
		// whatever, after 72 hours (switch off also wifi), wake up with 433Mhz remote only
		if (getTime()>60*60*72)
		{
			goSleepWaitOffOn();
		}
	}	
}


void dmaQuickBlack(void)
{
	initLedResetCodeInMemoryForDMA2(portbmem_flip,portcmem_flip);
	dmaLedDrive2(portbmem_flip,portcmem_flip);
	HAL_Delay(4);
	HAL_DMA_PollForTransfer(&hdma_tim8_ch1, HAL_DMA_FULL_TRANSFER, 20);
	HAL_DMA_PollForTransfer(&hdma_tim8_ch3, HAL_DMA_FULL_TRANSFER, 20);
	dmaPostLedDrive();
	HAL_Delay(4);
}

/* USER CODE END 0 */

int main(void)
{

  /* USER CODE BEGIN 1 */
  int firstPass;
	int flip_flop;
	float time;
	int cmd_id;
	uint8_t receivedCommand;
	int dtLimit;
	
	portbmem_ff[0] = portbmem_flip;
	portbmem_ff[1] = portbmem_flop;
	portcmem_ff[0] = portcmem_flip;
	portcmem_ff[1] = portcmem_flop;
	
	// on veut être sûr que lorsque les pin RST et EN WIFI passent en sortie, elles sont bien à 0.
	// Pour qu'il ne se mette pas à démarrer sans notre contrôle.
	GPIOA->ODR = GPIOB->ODR = GPIOC->ODR = 0;
	// tant que la clock n'est pas activée, ne sera pas latché (pas vérifié si c'est vraiment latché)
	
  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM6_Init();
  MX_TIM7_Init();
  MX_TIM8_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();

  /* USER CODE BEGIN 2 */

  GPIOA->ODR = GPIOB->ODR = GPIOC->ODR = 0;
  disableWIFI();
	enforceResetWIFI();

__HAL_DBGMCU_FREEZE_TIM3();
__HAL_DBGMCU_FREEZE_TIM6();
__HAL_DBGMCU_FREEZE_TIM7();
//__HAL_DBGMCU_FREEZE_TIM8(); // So that DMA transfer ends quick when step by step

	HAL_TIM_Base_Start(&htim6); // pour la base de temps principale. Avec une it par seconde. Secondes et 0.1ms step
	HAL_TIM_Base_Start(&htim7); // TIM7 à la micro seconde

// on a besoin de TIM7 pour les délais power up sequence

	if (!powerUPSequence())
	{
#ifdef POWER_MANAGER
		lowPowerCrash(CC_MAIN_POWER_UP_FAILED);
#endif
	}

//rose 0x80, 0x40, 0x40
	myColor[0] = 0xFF;
	myColor[1] = 0xFF;
	myColor[2] = 0xFF;
	myColor[0] = 0x80;
	myColor[1] = 0x40;
	myColor[2] = 0x40;

	generateUniformColor(raw_in,myColor);
//	generateBlack(raw_in);


	HAL_NVIC_SetPriority(TIM6_DAC_IRQn,2,2); // just below LED driver DMA
	TIM6->SR = 0; // Clear IT Flag
	
	HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
	TIM6->DIER |= TIM_DIER_UIE; // enable interrupt

  remoteHALInit(); // démarrage logique time out sur absence de PWM sur l'entrée télécommande
	// à la première interruption TIM6 (une seconde), va configurer PA0 en entrée avec IT sur front.
	// au premier front PA0, va disabler l'IT PA0 et indiquer la présence
	// si pas de front PA0, pas de présence, l'IT TIM6 va faire une demande gGoToSleep
	// elle sera prise en compte dans l'appel remoteManager()

	setPC13asInput();
	if (blueButtonIsDepressed()) // au boot, si bouton pressé, passe en mode controle manuel.
		wifiPathThru(); 

#ifdef SB17_NOW_10K
  setPC13asOutput();
#endif

  if (startupWIFI()==0)
		crash(CC_WIFI_STARTUP_FAILED);

	startRxCmdFlux(); // démarrage dma liaison série réception wifi
	
	setFlashFlipFlop();
	
/*
float getTime(void);
void setOffsetX(float X);
float updateOffsetX(void);
void setSpeedRPS(float RPS);	
*/
  setSpeedRPS(0); //59.0f/60.0f);//5.0f/60.0f);
	setOffsetX(0);
	
	firstPass = 1;
	flip_flop = 0;
	
	// init DMA memory flip and flop
	initLedResetCodeInMemoryForDMA2(portbmem_ff[0],portcmem_ff[0]);
	initLedResetCodeInMemoryForDMA2(portbmem_ff[1],portcmem_ff[1]);

	currentMode = 1;
	dynamicGenerator = 1;
	intensity = 128;
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

  while (1)
  {
//		setOffsetX(cos(time)); // for play
		receivedCommand = 0;
		g_limitFrameRate = 100;
		
		while (commandRx(&cmd_id,rxWifi_raw))
		{
			receivedCommand = 1;
			switch(cmd_id)
			{
				case CMD_POS : setOffsetX(*((float*)(rxWifi_raw))); RunLedToggle(); break;
				case CMD_SPD : setSpeedRPS(*((float*)(rxWifi_raw))); RunLedToggle(); break;
				case CMD_MOD : currentMode = *((uint32_t*)(rxWifi_raw)); dynamicGenerator = 1; RunLedToggle(); break;
				case CMD_RWC : if (checkUpdateFlash(rxWifi_raw)==0)
													break;
				case CMD_RAW : memcpy(raw_in,rxWifi_raw,RAW_SIZE); 
											 currentMode = 0; 
											 RunLedToggle(); 
											 break; // double copie, à éviter
				case CMD_INT : intensity = (uint8_t) *((uint32_t*)(rxWifi_raw)); dynamicGenerator = 1; break;
				case CMD_OFF : {
												while (TIM7->CNT<3000) 
											  {};
											  dmaWait();	// sweet stop	
											 dmaQuickBlack();	// pour éviter la rémanence image
											  powerDownListeningWifi(); 
											 }
											 break;
			}
		}

//		memcpy(raw,rxWifi_raw,RAW_SIZE+16);  checkUpdateFlash(raw);	readImageFromFlash(raw,2);
		
		// get current offset to apply. Need it to compute the partial offset on gaussian
		// also gets the time
		offsetX = updateOffsetX(&time); // garanties 0<=offsetX<NB_COLUMNS
		    
		// invoque auto image generator (takes control on startup and after 10 minutes of wifi inactivity (no commands received))
		// wifi user has priority
		cycler(time,receivedCommand);


		// the offset must be expressed as the sum of an integer in [0;NB_COLUMN-1] and an offset in ]-0.5;0.5]
		// offsetX = ioffsetX+goffsetX;
		// values between NB_COLUMN-0.5<values<NB_COLUMN are reached by ioffset = 0 and -0.5<goffset<0

		ioffsetX = offsetX; //integer part in [0;NB_COLUMNS-1]
		goffsetX = offsetX - ioffsetX; // float part in [0;1[
		
		if (goffsetX>0.5f)
		{
			goffsetX = goffsetX - 1.0f; // float part in ]-0.5;0.5]
			ioffsetX++; //integer part in [1;NB_COLUMNS]
			if (ioffsetX == NB_COLUMNS)
				ioffsetX = 0; //integer part in [0;NB_COLUMNS-1]
		}
				
		// Generate Image into raw
		if (dynamicGenerator)
		{
			dynamicGenerator = imageGenerator(currentMode,raw_in,time,intensity);
		}
		
			
#ifdef POWER_LIMITER
		if (!powerLimiter(raw_comp,raw_in,intensity))
			setIntensity(raw_comp,raw_in,intensity);	
#else
		setIntensity(raw_comp,raw_in,intensity);		
#endif
		
		// Process Image
		// Requires -0.5<=goffsetX<=0.5
		// needs the updated goffsetX
		filtreGaussienX(0.7f,NB_COLUMNS,NB_LINES, raw_comp, raw_out,-goffsetX);

		// Format Data for DMA
		// requires  0 <= ioffset < NB_COLUMNS
		portbmem = portbmem_ff[flip_flop];
		portcmem = portcmem_ff[flip_flop];
		formatMemoryForDMA2(raw_out,portbmem,portcmem,ioffsetX);

		// Wait for end of previous image DMA transfer before restarting a DMA transfer
		if (!firstPass)
		{
			dmaWait();
			t2 = TIM7->CNT;  // 1787µs. OK ! Mesuré 1.7ms à l'oscillo.
		}

// Position importante, cela assure que le DMA ne tourne plus au moment du power down.		
		// Si PWM télécommande pas détectée, STOP sans Wifi
		#ifdef REMOTE_MANAGER
			remoteManager();
		#endif

// Position importante, cela assure que le DMA ne tourne plus au moment du power down.
		// go to sleep anyway after 10 hours, with Wifi
		if (time>60*60*10)
		{
			powerDownListeningWifi();
		}		

		dtLimit = 1e6/g_limitFrameRate;
		while (TIM7->CNT<dtLimit) // limit rate
		{
		}
		
		// Start Send Image by DMA
		dmaLedDrive2(portbmem, portcmem); // Ne prend que 2µs YES !!

		t1 = TIM7->CNT; 
		TIM7->CNT = 0;	
		frameRate = 1e6/t1;
		
		firstPass = 0;
		flip_flop = 1 - flip_flop;


  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
  }

  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  __PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 180;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  HAL_PWREx_ActivateOverDrive();

  RCC_ClkInitStruct.ClockType = 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;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 3, 0);
}

/* TIM2 init function */
void MX_TIM2_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 0;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 0;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_Base_Init(&htim2);

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);

}

/* TIM3 init function */
void MX_TIM3_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0xFFFF;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 359;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;
  HAL_TIM_Base_Init(&htim3);

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);

}

/* TIM6 init function */
void MX_TIM6_Init(void)
{

  TIM_MasterConfigTypeDef sMasterConfig;

  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 9000;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 9999;
  HAL_TIM_Base_Init(&htim6);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig);

}

/* TIM7 init function */
void MX_TIM7_Init(void)
{

  TIM_MasterConfigTypeDef sMasterConfig;

  htim7.Instance = TIM7;
  htim7.Init.Prescaler = 89;
  htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim7.Init.Period = 0xFFFF;
  HAL_TIM_Base_Init(&htim7);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig);

}

/* TIM8 init function */
void MX_TIM8_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim8.Instance = TIM8;
  htim8.Init.Prescaler = 0;
  htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim8.Init.Period = 71;
  htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim8.Init.RepetitionCounter = 0;
  HAL_TIM_Base_Init(&htim8);

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig);

  HAL_TIM_OC_Init(&htim8);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig);

  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig);

  sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
  sConfigOC.Pulse = 20;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  HAL_TIM_OC_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_1);

  sConfigOC.Pulse = 30;
  HAL_TIM_OC_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_3);

}

/* USART1 init function */
void MX_USART1_UART_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;
  HAL_UART_Init(&huart1);

}

/* USART2 init function */
void MX_USART2_UART_Init(void)
{

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&huart2);

}

/** 
  * Enable DMA controller clock
  */
void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __DMA1_CLK_ENABLE();
  __DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
  HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
  HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
  HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
  HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
  HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
        * Free pins are configured automatically as Analog (this feature is enabled through 
        * the Code Generation settings)
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __GPIOC_CLK_ENABLE();
  __GPIOH_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();
  __GPIOB_CLK_ENABLE();
  __GPIOD_CLK_ENABLE();

  /*Configure GPIO pin : PC13 */
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : PC14 PC15 PC0 PC1 
                           PC2 PC3 PC4 PC5 
                           PC6 PC7 PC8 PC9 
                           PC10 PC11 PC12 */
  GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1 
                          |GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5 
                          |GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9 
                          |GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : PH0 PH1 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : GPIO0_ESP_Pin GLED_Pin PS_ON_Pin RST_ESP_Pin 
                           GPIO15_ESP_Pin EN_ESP_Pin */
  GPIO_InitStruct.Pin = GPIO0_ESP_Pin|GLED_Pin|PS_ON_Pin|RST_ESP_Pin 
                          |GPIO15_ESP_Pin|EN_ESP_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : GPIO2_ESP_Pin PW_KO_Pin */
  GPIO_InitStruct.Pin = GPIO2_ESP_Pin|PW_KO_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PB0 PB1 PB2 PB10 
                           PB12 PB13 PB14 PB15 
                           PB3 PB4 PB5 PB6 
                           PB7 PB8 PB9 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10 
                          |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15 
                          |GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6 
                          |GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PA12 */
  GPIO_InitStruct.Pin = GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PD2 */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

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

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

#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

/**
  * @}
  */ 

/**
  * @}
*/ 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
