// Make so you are able to set the sampling frequency - and change it real time!



// Remember to change the stm32f10x_conf.h to include the peripherals you need

/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include "stm32f10x.h"
#include "SSD2119.h"
#include "SSD2119_api.h"
#include "ads7843drv.h"
#include "fft.h"

#include <math.h> // Used for the DSP calculations

#define RED  	0xf800
#define GREEN	0x07e0
#define BLUE 	0x001f
#define WHITE	0xffff
#define BLACK	0x0000
#define YELLOW   0xFFE0

#define PI2  6.28318530717959

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

/* Private function prototypes -----------------------------------------------*/
long* CreateSine(long nfill, long Fs, long Freq1, long Freq2, long Ampli);

#define SampleBufferSize 1024 // Works best if this buffer size is the same as the FFT_LENGTH
#define SampleBufferShowSize 320
long SampleBuffer[SampleBufferSize];

u32 GetSamples(u16 SamplingDelay);
u16 CalculateSamplingDelay(u32 SamplingFreq);
float CalculateShownSines(u16 ShownSampleCount, u32 SamplingFreq, u32 freq);
u32 CalculateRequiredSamplingFreq(u16 ShownSampleCount, u32 freq, float ShownSines);

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ErrorStatus HSEStartUpStatus;
ADC_InitTypeDef ADC_InitStructure;

/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);

static __IO uint32_t TimingDelay;
void Delay(__IO uint32_t nTime);

void ADC_Configuration(void);

#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */


int TouchX, TouchY;

unsigned char  string_tmp[40];
u16 i;

/* Private function prototypes -----------------------------------------------*/
  
/* Private functions ---------------------------------------------------------*/


/*******************************************************************************
* Function Name  : main
* Description    : Main program
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
int main(void)
{
  /* System clocks configuration ---------------------------------------------*/
  RCC_Configuration();

  /* NVIC configuration ------------------------------------------------------*/
  NVIC_Configuration();

  /* GPIO configuration ------------------------------------------------------*/
  GPIO_Configuration(); 

  ADC_Configuration();

  Lcd_Configuration();
  Lcd_Initializtion();

  TP_Init();

  /* Setup SysTick Timer for 1 us (1000 us = 1 msec) interrupts  */                // Initialize the uC/OS-II tick interrupt 
  if (SysTick_Config(SystemFrequency / 1000000))
  { 
    /* Capture error */ 
    while (1);
  }

  Lcd_Clear(0xFFFF);
  Lcd_Rectangle(5,5,25,25,BLACK,FALSE);
  Lcd_Line(15,8,15,21,BLACK);
  Lcd_SetPoint(14,9,BLACK);
  Lcd_SetPoint(13,10,BLACK);
  Lcd_SetPoint(12,11,BLACK);
  Lcd_SetPoint(16,9,BLACK);
  Lcd_SetPoint(17,10,BLACK);
  Lcd_SetPoint(18,11,BLACK);

  Lcd_Rectangle(5,28,25,48,BLACK,FALSE);
  Lcd_Line(15,44,15,32,BLACK);
  Lcd_SetPoint(14,43,BLACK);
  Lcd_SetPoint(13,42,BLACK);
  Lcd_SetPoint(12,41,BLACK);
  Lcd_SetPoint(16,43,BLACK);
  Lcd_SetPoint(17,42,BLACK);
  Lcd_SetPoint(18,41,BLACK);

  u16 freq;
  u8 ScaledSineValue;  
  u32 RealSamplingFreq;
  float ShownSines;
  long* GeneratedSine; // Signed 32-bit integer (-2147483648 to 2147483647)
  u32 OriginalSampleFreq = 8000;
  u16 SamplingDelay = CalculateSamplingDelay(OriginalSampleFreq); // Sampling delay at 8000 Samples pr. second

while (1) {
  RealSamplingFreq = GetSamples(SamplingDelay);
  sprintf(string_tmp,"%i",RealSamplingFreq);
  Lcd_Text(30,20,string_tmp,6,BLACK,WHITE);

  for (i = 0; i < SampleBufferShowSize; i++) {
    Lcd_Line(i, 60, i, 180, WHITE);
    ScaledSineValue = SampleBuffer[i]>>(10 + 15); // SINE IS LEFT ALIGNED, AND TO GET THE 32-bit VALUE LOWER, WE RIGHT SHIFT IT!
    if (ScaledSineValue > 127) {        // Negative values    
      ScaledSineValue = (0xFF-ScaledSineValue) + 1; // Calculate absolute value
      Lcd_SetPoint(i, 127+ScaledSineValue, BLACK);    
    } else {  // Display positive values    
      Lcd_SetPoint(i, 127-ScaledSineValue, BLACK);
    }
  }
  u32* fft = compute_fft(SampleBuffer);
  // Find the fundamental
  u16 measured_f = fundamental_frequency(fft, RealSamplingFreq);
  // Filter the frequencies
  u16 filtered_f = moving_average(measured_f);
  sprintf(string_tmp,"%i",measured_f);
  Lcd_Text(100,0,string_tmp,6,BLACK,WHITE);

  ShownSines = CalculateShownSines(SampleBufferShowSize,measured_f,RealSamplingFreq);
  sprintf(string_tmp,"%.2f",ShownSines);
  Lcd_Text(200,0,string_tmp,29,BLACK,WHITE);

  //if (!(ShownSines < 7)) {
  //  SamplingDelay = CalculateSamplingDelay(CalculateRequiredSamplingFreq(SampleBufferShowSize,measured_f,6));
  //}

  if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0) {
    TouchX = Read_Y()/12;
    TouchY = Read_X()/17;

    if (TouchX >= 5 && TouchX <= 25 && TouchY >= 5 && TouchY <= 25) { 
      OriginalSampleFreq = OriginalSampleFreq + 100;    
      SamplingDelay = CalculateSamplingDelay(OriginalSampleFreq);
    }

    if (TouchX >= 5 && TouchX <= 25 && TouchY >= 28 && TouchY <= 48) { 
      OriginalSampleFreq = OriginalSampleFreq - 100;    
      SamplingDelay = CalculateSamplingDelay(OriginalSampleFreq);
    }
  sprintf(string_tmp,"X=%i, Y=%i",TouchX,TouchY);
  Lcd_Text(100,32,string_tmp,29,BLACK,WHITE);
  }
}
  
}

u32 GetSamples(u16 SamplingDelay) {
  u16 SamplesCount = 0;
  u32 OldTimingDelay;
  u32 SampleTime;

  unsigned int ADC_Read;
  
  TimingDelay = 1000000;
  while(SamplesCount < SampleBufferSize) {
    ADC_Read = ADC_GetConversionValue(ADC1);
    SampleBuffer[SamplesCount] =  (ADC_Read<<20)-0x7FFFFFFF; // Left shift the ADC value (0-4096) to a 32-bit value, and make it signed (-2,147,483,648 to +2,147,483,647)
    SamplesCount++;
  
    OldTimingDelay = TimingDelay;
    while ((TimingDelay+SamplingDelay) > OldTimingDelay); // Delay
        
    if (TimingDelay == 0) {
      return 0;
    }
  }

  SampleTime = 1000000-TimingDelay; // Sample time in us
  return (1000000/SampleTime)*SampleBufferSize; // Return Sampling Frequency (1000 msec (=1000000 us) / Sample time) * Buffer Size
}

u16 CalculateSamplingDelay(u32 SamplingFreq) {
  return 937274*pow(SamplingFreq,-0.995);
}

float CalculateShownSines(u16 ShownSampleCount, u32 freq, u32 SamplingFreq) {
  u32 tmp = (ShownSampleCount*freq);  
  return ((float)(tmp) / (float)(SamplingFreq));  // (Samples shown / sample frequency) * frequency = shown sine wave count*filtered_f)
}

u32 CalculateRequiredSamplingFreq(u16 ShownSampleCount, u32 freq, float ShownSines) {
  u32 tmp = (ShownSampleCount*freq);  
  return (tmp / ShownSines);  // (Samples shown / sample frequency) * frequency = shown sine wave count*filtered_f)
}
  
/**
  * @brief  Produces a combination of two sinewaves as input signal
  * @param nfill: length of the array holding input signal
  *   Fs: sampling frequency
  *   Freq1: frequency of the 1st sinewave
  *   Freq2: frequency of the 2nd sinewave
  *   Ampli: scaling factor
  * @retval : None
  */
long* CreateSine(long nfill, long Fs, long Freq1, long Freq2, long Ampli)
{
  uint32_t i;
  long TmpSine[nfill];
  float fFs, fFreq1, fFreq2, fAmpli;
  float fZ,fY;

  fFs = (float) Fs;
  fFreq1 = (float) Freq1;
  fFreq2 = (float) Freq2;
  fAmpli = (float) Ampli;

  for (i=0; i < nfill; i++)
  {
    fY = sin(PI2 * i * (fFreq1/fFs)) + sin(PI2 * i * (fFreq2/fFs));
    fZ = fAmpli * fY;
    TmpSine[i]= ((short)fZ) << 16 ;  /* sine_cosine  (cos=0x0) */
  }
  
  return TmpSine;
}


/*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : Configures the different system clocks.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RCC_Configuration(void)
   {
   /* RCC system reset(for debug purpose) */
   RCC_DeInit();

   /* Enable HSE */
   RCC_HSEConfig(RCC_HSE_ON);

   /* Wait till HSE is ready */
   HSEStartUpStatus = RCC_WaitForHSEStartUp();

   if(HSEStartUpStatus == SUCCESS)
      {
      /* Enable Prefetch Buffer */
      FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

      /* Flash 2 wait state */
      FLASH_SetLatency(FLASH_Latency_2);

      /* HCLK = SYSCLK */
      RCC_HCLKConfig(RCC_SYSCLK_Div1); 

      /* PCLK2 = HCLK */
      RCC_PCLK2Config(RCC_HCLK_Div1); 

      /* PCLK1 = HCLK/2 */
      RCC_PCLK1Config(RCC_HCLK_Div2);

      /* PLLCLK = 8MHz * 9 = 72 MHz */
      RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_16);

      /* Enable PLL */ 
      RCC_PLLCmd(ENABLE);

      /* Wait till PLL is ready */
      while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
         {;}

      /* Select PLL as system clock source */
      RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

      /* Wait till PLL is used as system clock source */
      while(RCC_GetSYSCLKSource() != 0x08)
         {;}
      }

   /* Enable peripheral clocks --------------------------------------------------*/
   /* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG and AFIO clocks */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC 
         | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG 
         | RCC_APB2Periph_AFIO, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
   }


/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : Configures the different GPIO ports.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  /*------------------- Resources Initialization -----------------------------*/
  /* GPIO Configuration */
  /* Configure PD.02 as Output push-pull */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  /* Configure PA.01 (ADC Channel1) as analog input -------------------------*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void ADC_Configuration(void)
{
  /* ADC1 configuration ------------------------------------------------------*/
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel1 configuration */ 
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
  
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);

  /* Enable ADC1 reset calibration register */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibaration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));
  
  /* Start ADC1 Software Conversion */ 
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  
  while(ADC_GetSoftwareStartConvStatus(ADC1));
}      


/*******************************************************************************
* Function Name  : NVIC_Configuration
* Description    : Configures Vector Table base location.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void NVIC_Configuration(void)
{
#ifdef  VECT_TAB_RAM  
  /* Set the Vector Table base location at 0x20000000 */ 
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */ 
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
#endif
}



void Delay(__IO uint32_t nTime)
{ 
  TimingDelay = nTime*1000; // As nTime is msec, but our SysTick is set to us, we have to multiply with 1000

  while(TimingDelay != 0);
}

/**
  * @brief  Decrements the TimingDelay variable.
  * @param  None
  * @retval None
  */
void TimingDelay_Decrement(void)
{
  if (TimingDelay != 0x00)
  { 
    TimingDelay--;
  }
}





#ifdef  DEBUG
/*******************************************************************************
* Function Name  : assert_failed
* Description    : Reports the name of the source file and the source line number
*                  where the assert error has occurred.
* Input          : - file: pointer to the source file name
*                  - line: assert error line source number
* Output         : None
* Return         : None
*******************************************************************************/
void assert_failed(u8* file, u32 line)
{ 
  /* 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) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

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