#include "stm32f4xx_hal.h"
#include "led_driver.h"
#include "globals.h"
#include "remote.h"

uint32_t gSecondCounter = 0;
//uint32_t g100usSecondCounter = 0;
float speedRPS = 0;
float l_offsetX = 0; // modulo NB_COLUMNS
float startTimeOffset = 0;
extern TIM_HandleTypeDef htim6;	
// timers

/*
 F446
 TIM8 (180Mhz,APB2) pour le DMA vers LEDs. Count to 71 pour 0.4µs
 TIM7 (basic,90Mhz, APB1) pour mesures de délai à la microseconde
 TIM3 (90Mhz,APB1) pour des délais de 1 seconde (détection ON/OFF télécommande). Pas utilisé je crois
 TIM6 (basic 90Mhz, APB1) pour mesures de délai à 100 microseconde près, fait un tour par seconde, utilisé pour la base de temps principale
 TIM6 prescaler 9000, counter period 10000-1
 
 F746
 TIM8 (108Mhz,APB2) pour le DMA vers LEDs. Count to 42 pour 0.4µs
 TIM7 (basic,54Mhz, APB1) pour mesures de délai à la microseconde
 TIM3 (54Mhz,APB1) pour des délais de 1 seconde (détection ON/OFF télécommande). Pas utilisé je crois
 TIM6 (basic 54Mhz, APB1) pour mesures de délai à 100 microseconde près, fait un tour par seconde, utilisé pour la base de temps principale
 TIM6 prescaler 9000, counter period 10000-1
 
*/

// TIM1,8,9,10,11 sont sur APB2 (180Mhz)
// TIM2,3,4,5,6,7,12,13,14 est sur APB1(slow, 90Mhz)

// Precision of time in sec in a single precision float
// after 16777216 sec (4600 hours) gives only integer precision (too bad)
// after 167772.16 sec (46 hours) less than 1/100sec precision. Should not go beyond.

float getTime(void)
{ 
	uint16_t time6;
	uint32_t l_SecondCounter;
	
//	HAL_TIM_Base_Stop(&htim6);
	TIM6->CR1 &= ~TIM_CR1_CEN;
	time6 = TIM6->CNT;
	l_SecondCounter = gSecondCounter;
//	HAL_TIM_Base_Start(&htim6);
	TIM6->CR1 |= TIM_CR1_CEN;
	return l_SecondCounter + time6*0.0001f;
}

void setOffsetX(float X)
{
	//puts back in [0..1[
	if (X<=-1)
		X = 0;
	else
	{
		if (X>=1)
			X = 0;
		else if (X<0)
			X+=1;
	}
	l_offsetX = X*NB_COLUMNS;
	startTimeOffset = getTime();
}

// This function is supposed to be called at least before each frame display
float updateOffsetX(float *time)
{
	*time = getTime();
	
	if (speedRPS==0)
	{
		startTimeOffset = *time;
		return l_offsetX;
  }		
	
	l_offsetX = l_offsetX + (*time-startTimeOffset)*speedRPS;
	
	while (l_offsetX>=NB_COLUMNS)
	{
		l_offsetX-=NB_COLUMNS;
	}
	while (l_offsetX<0)
	{
		l_offsetX+=NB_COLUMNS;
	}
	startTimeOffset = *time;
	
	return l_offsetX;
}

void setSpeedRPS(float RPS)
{
	float l_time;
	updateOffsetX(&l_time); // update position with previous speed just before changing it.
	if (RPS>1)
		RPS = 1;
	if (RPS<-1)
		RPS = -1;
	speedRPS = RPS*NB_COLUMNS;
}


//#define quickWaitXus(x) {TIM6->CNT = 0;while(TIM6->CNT<x);}

void waitBlocking(uint16_t x_us)
{
	TIM7->CNT = 0;	
	while (TIM7->CNT<x_us);
}


void myWait1ms(int dtms)
{
	int i;

	for (i=0;i<dtms;i++)
			waitBlocking(1000);
}


void setPC13asInput(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
	// Mise de la broche bouton poussoir bleu PC13 en entrée
	// La pression sur le bouton poussoir met à la masse.
  /*Configure GPIO pin : PW_OK_Pin */
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

void setPC13asOutput(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;

  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_MEDIUM;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
/*
 446RE

 Equipment Options for SB17

 Solution 1 : SB17 equipped with a 10K resistor and R9 = 0 ohm
 this way, when PC13 is an input, the push button state can be read 
 and when PC13 is an output, it will drive LED28
 
 Solution 2 : SB17 is removed. In that case, the push button is not functionnal
 and PC13 can only drive LED28

 Solution 3 : SB17 remains equipped with a 0hms (the way it arrives from ST factory)
 in that case : PC13 must never be an output, beware in the code.
 PC13 should always be an input, the push button state can be read
 but LED28 cannot be driven

  746ZG

  Can leave SB173 closed
*/

uint8_t blueButtonIsDepressed(void)
{
#ifdef STM32F746xx
	return (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)==GPIO_PIN_SET);
#endif

#ifdef STM32F446xx	
	return (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)==GPIO_PIN_RESET);
#endif	
}



// fait clignoter la led RUN avec un code lisible
// led run == PB8
void crash(uint8_t crash_code)
{
	int i,j;

	for(i=0;i<20;i++)
	{
		RunLedOn();
		myWait1ms(40);
		RunLedOff();
		myWait1ms(20);
		RunLedOn();
		myWait1ms(40);
		RunLedOff();
		myWait1ms(400);

		for (j=0;j<8;j++)
		{
			if (crash_code & (1<<(7-j)))
			{
				RunLedOn();
			}
			// 100ms
			myWait1ms(100);
			RunLedOff();
			myWait1ms(400);
		}
	}
	powerDownListeningWifi();
	
}

void lowPowerCrash(uint8_t crash_code)
{
	crash(crash_code);
}


