#include "Fader.h"

void Fader_IO_Init (void);
void Fader_Timer_Init (void);
void Fader_ADC_Init (void);
void Fader_DMA_Init (void);
void Fader_DMA_NVIC_Init (void);

volatile uint16_t     ADC_DMA_Buffer[16];

extern volatile uint16_t G_FaderValueRegister [NUMBER_OF_FADER];
extern volatile uint8_t G_ISPC_RegisterArray [256];

extern volatile uint8_t G_ADC_State;
extern volatile uint8_t G_Values_Stable;


/*****************************************************************************************************
 *	Brief : 																						 *
 *																									 *
 *	@Param : none			 																		 *
 *																									 *
 *	@ReturnValue : 					         								         				 *
 *****************************************************************************************************/
void Fader_IO_Init (void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);									//GPIOA Peripheral clock enable
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);									//GPIOB Peripheral clock enable
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);									//GPIOC Peripheral clock enable

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

	RCC_ADCCLKConfig(RCC_ADCCLK_HSI14);              									//Use internal 14 Mhz RC oscillator as ADC clock
	RCC_HSI14Cmd(ENABLE);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	GPIO_InitStructure.GPIO_Pin = (FADER_1 | FADER_2 | FADER_3 | FADER_4 |				// Configure GPIOA Pins 0,1,2,3,4,5,6,7 as analog input
								   FADER_5 | FADER_6 | FADER_7 | FADER_8 );
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	GPIO_InitStructure.GPIO_Pin = (FADER_9 | FADER_10 );								// Configure GPIOB Pins 0,1 as analog input
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	GPIO_InitStructure.GPIO_Pin = (FADER_11 | FADER_12 | FADER_13 | FADER_14 |			// Configure GPIOC Pins 0,1,2,3,4,5,6,7 as analog input
								   FADER_15 | FADER_16 );
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

/*****************************************************************************************************
 *	Brief : 																						 *
 *																									 *
 *	@Param : none			 																		 *
 *																									 *
 *	@ReturnValue : 					         								         				 *
 *****************************************************************************************************/
void Fader_ADC_Init (void)
{
	ADC_InitTypeDef  ADC_InitStructure;

	ADC_DeInit(ADC1);
	ADC_StructInit(&ADC_InitStructure);

	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;            				//Resolution 12 bit
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;								//Cont Conv Mode
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;            				//Data alignment right (Bit 11 to 0)
	ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;        			//Scan direction Ch0 to Ch15
	ADC_Init(ADC1, &ADC_InitStructure);


	ADC_ChannelConfig(ADC1, ADC_Channel_0 | ADC_Channel_1| ADC_Channel_2| ADC_Channel_3 |
							ADC_Channel_4 | ADC_Channel_5| ADC_Channel_6| ADC_Channel_7 |
							ADC_Channel_8 | ADC_Channel_9| ADC_Channel_10| ADC_Channel_11 |
							ADC_Channel_12 | ADC_Channel_13 | ADC_Channel_14 | ADC_Channel_15,
							ADC_SampleTime_13_5Cycles);

	ADC_Cmd(ADC1, ENABLE);

	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));									//Wait until ADCEN bit is set
}

/*****************************************************************************************************
 *	Brief : 																						 *
 *																									 *
 *	@Param : none			 																		 *
 *																									 *
 *	@ReturnValue : 					         								         				 *
 *****************************************************************************************************/
void Fader_DMA_Init (void)
{
	DMA_InitTypeDef         DMA_InitStructure;

	ADC_DMACmd(ADC1, ENABLE);														//Enable ADC DMA

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);								//Enable clock for DMA

	DMA_DeInit(DMA1_Channel1);														//Deinitialize DMA Channel 1

	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address;    		//ADC Address
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_DMA_Buffer;      			//ADC Buffer
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;              				//ADC -> RAM
	DMA_InitStructure.DMA_BufferSize = 16;                    						//Buffer Size 18
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;				//No peripheral increment
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;							//Memory increment
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  	//ADC width of data = 16bit
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;      		//RAM width of data = 16bit
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                					//Use normal mode to update buffer
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;              				//Use high priority
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                					//Disable memory to memory mode
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);

	DMA_Cmd(DMA1_Channel1, ENABLE);													//Enable Channel 1 for DMA

	DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

	ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);							//Request Mode is ADC DMA One shot mode

}

/*****************************************************************************************************
 *	Brief : 																						 *
 *																									 *
 *	@Param : none			 																		 *
 *																									 *
 *	@ReturnValue : 					         								         				 *
 *****************************************************************************************************/
void Fader_DMA_NVIC_Init (void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
	NVIC_Init(&NVIC_InitStructure);

}



/*****************************************************************************************************
 *	Brief : 																						 *
 *																									 *
 *	@Param : none			 																		 *
 *																									 *
 *	@ReturnValue : 					         								         				 *
 *****************************************************************************************************/
void Fader_Init (void)
{
	Fader_IO_Init ();
	Fader_ADC_Init ();
	Fader_DMA_Init ();
	Fader_DMA_NVIC_Init ();

	ADC_StartOfConversion(ADC1);													//Start conversion

}

/*****************************************************************************************************
 *	Brief : 																						 *
 *																									 *
 *	@Param : none			 																		 *
 *																									 *
 *	@ReturnValue : 					         								         				 *
 *****************************************************************************************************/
void Fader_Update_Values (void)
{
	static uint8_t AveragingIteration = 0;
		static uint32_t FaderAveraged [NUMBER_OF_FADER] = {0};
		uint8_t FaderCount = 0;

		if (G_ADC_State == CONVERSION_READY)
		{
			AveragingIteration++;

			if(AveragingIteration < ADC_AVERAGING)
			{
				for (FaderCount = 0; FaderCount < NUMBER_OF_FADER; FaderCount++)
				{
					FaderAveraged[FaderCount] += ADC_DMA_Buffer[FaderCount];
				}
			}
			else
			{
				for (FaderCount = 0; FaderCount < NUMBER_OF_FADER; FaderCount++)
				{
					G_FaderValueRegister[FaderCount] = FaderAveraged[FaderCount] / ADC_AVERAGING;
				}

				memset(FaderAveraged, 0, sizeof(FaderAveraged));

				AveragingIteration = 0;

				GPIOB->ODR ^= GPIO_Pin_15;												//Speed measurement
			}

			G_ADC_State = CONVERSION_NOT_READY;
			G_Values_Stable = TRUE;

			//PWM_PCA9685_Set_LED_Brightness_12Bit(PCA9685_Chip1,1, 0, G_FaderValueRegister[0]);



			ADC_StartOfConversion(ADC1);													//Start conversion
		}
}

void Fader_Update_Registers_1 (void)
{
	uint8_t FaderCount = 0;

	if (G_Values_Stable == TRUE)
	{

		for (FaderCount = 0; FaderCount < NUMBER_OF_FADER; FaderCount++)
		{
			G_ISPC_RegisterArray [(ISP_FADER_REG_H_OFFSET + (FaderCount*2))] = ((G_FaderValueRegister[FaderCount] & 0xFF00) >> 8);
			G_ISPC_RegisterArray [(ISP_FADER_REG_L_OFFSET + (FaderCount*2))] = (G_FaderValueRegister[FaderCount] & 0x00FF);
		}

		G_Values_Stable = FALSE;
	}
}





void DMA1_Channel1_IRQHandler (void)
{
	ADC_StopOfConversion(ADC1);															//Temporary Stop Conversations

	if (DMA_GetITStatus(DMA1_IT_TC1) != RESET)
	{
		DMA_ClearITPendingBit(DMA1_IT_TC1);
		G_ADC_State = CONVERSION_READY;
	}

}













/*
if (G_Values_Stable == TRUE)
{
	for (FaderCount = 0; FaderCount < NUMBER_OF_FADER; FaderCount++)
	{
		FaderValueOld = (G_ISPC_RegisterArray [(ISP_FADER_REG_H_OFFSET + (FaderCount*2))] << 8) +
						(G_ISPC_RegisterArray [(ISP_FADER_REG_L_OFFSET + (FaderCount*2))]);

		FaderValueNew = G_FaderValueRegister[FaderCount];

		FaderValueDelta = fabs(FaderValueOld - FaderValueNew);

		if (FaderValueDelta >= MINIMUM_FADERCHANGE_THRESHOLD)
		{
			Test+= 1;

			if (FaderCount < 8)
			{
				G_ISPC_RegisterArray[ISP_FADER_1_8_CHANGE_REGISTER] |= (1<<FaderCount);
			}
			else
			{
				G_ISPC_RegisterArray[ISP_FADER_9_16_CHANGE_REGISTER] |= (1<<(FaderCount-8));
			}
		}
		else
		{
			if (FaderCount < 8)
			{
				G_ISPC_RegisterArray[ISP_FADER_1_8_CHANGE_REGISTER] &= (0xFF & (0<<FaderCount));
			}
			else
			{
				G_ISPC_RegisterArray[ISP_FADER_9_16_CHANGE_REGISTER] &= (0xFF & (0<<(FaderCount-8)));
			}
		}

		G_ISPC_RegisterArray [(ISP_FADER_REG_H_OFFSET + (FaderCount*2))] = ((G_FaderValueRegister[FaderCount] & 0xFF00) >> 8);
		G_ISPC_RegisterArray [(ISP_FADER_REG_L_OFFSET + (FaderCount*2))] = (G_FaderValueRegister[FaderCount] & 0x00FF);
	}

	G_Values_Stable = FALSE;
}
*/























/*****************************************************************************************************
 *	Brief : 																						 *
 *																									 *
 *	@Param : none			 																		 *
 *																									 *
 *	@ReturnValue : 					         								         				 *
 *****************************************************************************************************/
/*
void Fader_Update_Registers (uint16_t FaderValue, uint8_t FaderCount)
{
	uint8_t FaderValueHighTemp = 0;
	uint8_t FaderValueLowTemp = 0;
	uint8_t FaderChangeMask = 0;
	uint16_t FaderValueReference = 0;
	static uint16_t FaderValuesDebounce1 [NUMBER_OF_FADER];

	FaderValueHighTemp = G_ISPC_RegisterArray [(ISP_FADER_REG_H_OFFSET + (FaderCount*2))];						//Get last stored value from fader register
	FaderValueLowTemp = G_ISPC_RegisterArray [(ISP_FADER_REG_L_OFFSET + (FaderCount*2))];						//Get last stored value from fader register

	FaderValueReference |= ((FaderValueHighTemp << 8) & 0xFF00);												//Set as reference value
	FaderValueReference |=  (FaderValueLowTemp & 0x00FF);														//Set as reference value

	if (FaderValuesDebounce1 [FaderCount] > FaderValueReference)											//Debounce stage 1 value larger than reference
	{
		if (FaderValue > FaderValueReference)																//New fader value also larger than reference
		{																									//-> Slide up detected
			G_ISPC_RegisterArray [(ISP_FADER_REG_H_OFFSET + (FaderCount*2))] = ((FaderValue & 0xFF00)>>8);	//Update fader high register
			G_ISPC_RegisterArray [(ISP_FADER_REG_L_OFFSET + (FaderCount*2))] = (FaderValue & 0x00FF);		//Update fader low register

			if (FaderCount <= 7)																			//Fader 1 to 8 changed, set corresponding
			{																								//bit in Fader 1 to 8 change register
				FaderChangeMask = G_ISPC_RegisterArray [ISP_FADER_1_8_CHANGE_REGISTER];
				FaderChangeMask |= (1<<FaderCount);
				G_ISPC_RegisterArray[ISP_FADER_1_8_CHANGE_REGISTER] = FaderChangeMask;
			}
			else																							//Fader 9 to 16 changed, set corresponding
			{																								//bit in Fader 9 to 16 change register
				FaderChangeMask = G_ISPC_RegisterArray [ISP_FADER_9_16_CHANGE_REGISTER];
				FaderChangeMask |= (1<<(FaderCount-8));
				G_ISPC_RegisterArray[ISP_FADER_9_16_CHANGE_REGISTER] = FaderChangeMask;
			}

		}
	}

	if (FaderValuesDebounce1 [FaderCount] < FaderValueReference)											//Debounce stage 1 value larger than reference
	{
		if (FaderValue < FaderValueReference)																//New fader value also smaller than reference
		{																									//-> Slide down detected
			G_ISPC_RegisterArray [(ISP_FADER_REG_H_OFFSET + (FaderCount*2))] = ((FaderValue & 0xFF00)>>8);	//Update fader high register
			G_ISPC_RegisterArray [(ISP_FADER_REG_L_OFFSET + (FaderCount*2))] = (FaderValue & 0x00FF);		//Update fader low register

			if (FaderCount <= 7)																			//Fader 1 to 8 changed, set corresponding
			{																								//bit in Fader 1 to 8 change register
				FaderChangeMask = G_ISPC_RegisterArray [ISP_FADER_1_8_CHANGE_REGISTER];
				FaderChangeMask |= (1<<FaderCount);
				G_ISPC_RegisterArray[ISP_FADER_1_8_CHANGE_REGISTER] = FaderChangeMask;
			}
			else																							//Fader 9 to 16 changed, set corresponding
			{																								//bit in Fader 9 to 16 change register
				FaderChangeMask = G_ISPC_RegisterArray [ISP_FADER_9_16_CHANGE_REGISTER];
				FaderChangeMask |= (1<<(FaderCount-8));
				G_ISPC_RegisterArray[ISP_FADER_9_16_CHANGE_REGISTER] = FaderChangeMask;
			}
		}
	}
	else																									//No slider movement
	{
		if (FaderCount <= 7)					// Fader 1 to 8 changed not, reset corresponding bit in Fader 1 to 8 change register
		{
			FaderChangeMask = G_ISPC_RegisterArray [ISP_FADER_1_8_CHANGE_REGISTER];
			FaderChangeMask &= (0xFF & 0<<FaderCount);
			G_ISPC_RegisterArray[ISP_FADER_1_8_CHANGE_REGISTER] = FaderChangeMask;
		}
		else									// Fader 9 to 16 changed not, reset corresponding bit in Fader 1 to 8 change register
		{
			FaderChangeMask = G_ISPC_RegisterArray [ISP_FADER_9_16_CHANGE_REGISTER];
			FaderChangeMask &= (0xFF & 0<<(FaderCount-8));
			G_ISPC_RegisterArray[ISP_FADER_9_16_CHANGE_REGISTER] = FaderChangeMask;
		}
	}

	FaderValuesDebounce1 [FaderCount] = FaderValue;
}

*/
