#include "STM32_AddressDefs.h"

#define USARTx_SR USART1_SR
#define USARTx_DR USART1_DR

#define LED             ( 1 << 5 )                // PB5: LED D2

int ShiftVal;

char RecvData(){
  volatile int c;

  while (!(USARTx_SR & 0x0020));
  c = ((int)(USARTx_DR & 0x1FF));

  return (char )c;
}

void SendData(char data){
  while (!(USARTx_SR & 0x0080));
  USARTx_DR = ((unsigned int)data & 0x1FF);
}

void USART_handler(){
  char c;
  c= RecvData();

  if(c == '0'){
    SendData('O');
    SendData('F');
    SendData('F');
    SendData('\n');
    SendData('\r');
    GPIOB_ODR &= ~LED;
    ShiftVal --;
    return;
  }
  if(c == '1'){
    SendData('O');
    SendData('N');
    GPIOB_ODR |= LED;
    SendData('\n');
    SendData('\r');
    ShiftVal ++;
    return;
  }
  
  SendData('E');
  SendData('R');
  SendData('R');
  SendData('\n');
  SendData('\r');

}

#define __EFI_ACR_Val 0x00000012
#define __RCC_CR_VAL  0x01010082
#define __RCC_CFGR_VAL 0x00118402
#define __NVIC_VTOR_VAL 0x00000000
#define __SYSTICK_CTRL_VAL 0x00000002
#define __SYSTICK_PERIOD 0x0000000A
#define CFGR_HPRE_MASK 0x000000F0 // Mask for AHB prescaler
#define __HCLKPRESC  0x00000000
#define __SYSTICKCLK (__HCLK>>3)
#define __HSE 12000000UL
#define CFGR_PLLMULL_MASK 0x003C0000 // Mask for PLL multiplier
#define __PLLMULL (((__RCC_CFGR_VAL & CFGR_PLLMULL_MASK) >> 18) + 2)
#define __SYSCLK  (__HSE * __PLLMULL)  // SYSCLK = HSE * pllmul
#define __HCLK        (__SYSCLK)
#define CFGR_PRE2_MASK 0x00003800 // Mask for APB2 prescaler 
#define __PCLK2       (__HCLK)


#define __USART1_BAUDRATE         115200 //  4
#define __USART1_DATABITS         0x00000000
#define __USART1_STOPBITS         0x00000000
#define __USART1_PARITY           0x00000000
#define __USART1_FLOWCTRL         0x00000000

#define __DIV(__PCLK, __BAUD)       ((__PCLK*25)/(4*__BAUD))
#define __DIVMANT(__PCLK, __BAUD)   (__DIV(__PCLK, __BAUD)/100)
#define __DIVFRAQ(__PCLK, __BAUD)   (((__DIV(__PCLK, __BAUD) - (__DIVMANT(__PCLK, __BAUD) * 100)) * 16 + 50) / 100)
#define __USART_BRR(__PCLK, __BAUD) ((__DIVMANT(__PCLK, __BAUD) << 4)|(__DIVFRAQ(__PCLK, __BAUD) & 0x0F))

unsigned  int ADC_ConvertedValue;
unsigned  char Clock1s;
unsigned long timetick;
unsigned char leds = 0x01;
unsigned long ticks;

void SysTick_Handler (void) {
  if (ticks++ >= 99) { // Set Clock1s to 1 every 1 second
    ticks   = 0;
    Clock1s = 1;
  }
}


void SendIntHex(int val){
  int i;
  char c;

  for(i=0;i<4;i++){
    switch((val>>((3-i)<<2))&0xF){
    case 0 : c = '0'; break;
    case 1 : c = '1'; break;
    case 2 : c = '2'; break;
    case 3 : c = '3'; break;
    case 4 : c = '4'; break;
    case 5 : c = '5'; break;
    case 6 : c = '6'; break;
    case 7 : c = '7'; break;
    case 8 : c = '8'; break;
    case 9 : c = '9'; break;
    case 10 : c = 'A'; break;
    case 11 : c = 'B'; break;
    case 12 : c = 'C'; break;
    case 13 : c = 'D'; break;
    case 14 : c = 'E'; break;
    case 15 : c = 'F'; break;
    default: c = 'X';
    }
    SendData(c);
  }
  SendData('\r');
  SendData('\n');
}


void BreakPoint_Handler(){
  SendData('B');
  SendData('K');
  SendData('P');
  SendData('T');
  SendData('\r');
  SendData('\n');

  while(1);
}
 
int main(){

  int i;

  // EFI Configuration
  FLASH_ACR = __EFI_ACR_Val; // set access control register 
  
  // Clock Configuration
  RCC_CFGR = __RCC_CFGR_VAL; // set clock configuration register
  RCC_CR   = __RCC_CR_VAL; // set clock control register
  
  while ((RCC_CR & 0x00020000) == 0){} // Wait for HSERDY = 1 (HSE is ready)
  while ((RCC_CR & 0x02000000) == 0){} // Wait for PLLRDY = 1 (PLL is ready)
  
  /* Wait till SYSCLK is stabilized (depending on selected clock) */
  while ((RCC_CFGR & 0xC) != ((__RCC_CFGR_VAL<<2) & 0xC));

  // NVIC Configuration
  SCB_ExceptionTableOffset = (__NVIC_VTOR_VAL & 0x1FFFFF80); // set register

  // SysTick Configuration
#if ((__SYSTICK_PERIOD*(__SYSTICKCLK/1000)-1) > 0xFFFFFF) // reload value to large
   #error "Reload Value to large! Please use 'HCLK/8' as System Timer clock source or smaller period"
#else
  SysTick_LOAD  = __SYSTICK_PERIOD*(__SYSTICKCLK/1000)-1; // set reload register
  SysTick_CTRL  = __SYSTICK_CTRL_VAL; // set clock source and Interrupt enable

  SysTick_VAL   =  0; // clear  the counter

  SysTick_CTRL |= 0x1; // enable the counter
#endif

  // GPIO Configuration
  // GPIO Port A
  RCC_APB2ENR |= 0x00000004; // enable clock for GPIOA
  GPIOA_CRL = 0x00000000; // set Port configuration register low
  GPIOA_CRH = 0x00000000; // set Port configuration register high

  // GPIO Port B
  RCC_APB2ENR |= 0x00000008; // enable clock for GPIOB
  GPIOB_CRL = 0x00300000; // set Port configuration register low
  GPIOB_CRH = 0x00000000; // set Port configuration register high
  

  // USART Configuration
  // USART1 used
  AFIO_MAPR   &= ~(1 << 2); // clear USART1 remap
  // USART1 no remap
  RCC_APB2ENR |= 0x00000004; // enable clock for GPIOA
  GPIOA_CRH &= ~(0xFFUL  << 4); // Clear PA9, PA10
  GPIOA_CRH |=  (0x0BUL  << 4); // USART1 Tx (PA9)  alternate output push-pull
  GPIOA_CRH |=  (0x04UL  << 8); // USART1 Rx (PA10) input floating

  RCC_APB2ENR |= 0x00004000; // enable clock for USART1
  
  USART1_BRR = __USART_BRR(__PCLK2, __USART1_BAUDRATE); // set baudrate
  USART1_CR1 = __USART1_DATABITS; // set Data bits
  USART1_CR2 = __USART1_STOPBITS; // set Stop bits
  USART1_CR1 |= __USART1_PARITY; // set Parity
  USART1_CR3 = __USART1_FLOWCTRL; // Set Flow Control
  
  USART1_CR1 |= (0x00000004 | 0x00000008); // RX, TX enable

  GPIOB_ODR |= LED;

  // USART interrupts used
  USART1_CR1 |= (0x1<<5);
  USART1_CR2 |= 0x0;
  USART1_CR3 |= 0x0;
  //  NVIC_Enable[1] |= (1 << (0x25 & 0x1F)); // enable interrupt
  *((volatile unsigned int *)0xE000E104) |= (1 << 5); // enable interrupt
  USART1_CR1 |= 0x00002000; // USART enable

  // Main
  // initialise A/D converter
  RCC_AHBENR |= (1<<0); // enable periperal clock for DMA
  DMA1_CMAR  = (unsigned int)&ADC_ConvertedValue; // set channel1 memory address
  DMA1_CPAR  = (unsigned int)&(ADC1_DR); // set channel1 peripheral address
  DMA1_CNDTR = 1; // transmit 1 word
  DMA1_CCR   = 0x00002520; // configure DMA channel
  DMA1_CCR  |= (1 << 0); // DMA Channel 1 enable
  RCC_APB2ENR |= (1<<9); // enable periperal clock for ADC1
  ADC1_SQR1 &= ~0x00F00000; // only one conversion
  ADC1_SMPR2 &= 0x00000038; // clear bits 3..5 (channel1)
  ADC1_SMPR2 |= 0x00000028; // set sample time (55,5 cycles)
  ADC1_SQR3  &= 0x0000001F; // clear bits 0..4
  ADC1_SQR3  |= 0x00000001; // set rank
  ADC1_CR1   =  0x00000100; // use independant mode, SCAN mode
  ADC1_CR2   =  0x000E0103; // use data align right,continuous conversion
  // enable ADC, DMA mode, no external Trigger
  ADC1_CR2  |=  0x00500000; // start SW conversion

  // For BKPT instraction test
  //asm(".short 0xbebe");

  int AD_value;
  int AD_scaled_ex = 0;
  int AD_scaled;
  ShiftVal = 20;

  i = 0;
  while (1) { // Loop forever
    AD_value  = ADC_ConvertedValue; // Read AD value
    AD_scaled = AD_value >> 6; // AD value scaled to 0 .. 78 (lines on LCD)
    if (AD_scaled != AD_scaled_ex) { // If new AD value different than old
      AD_scaled_ex = AD_scaled;
    }

    if (Clock1s) {
      Clock1s = 0;
      SendIntHex(AD_value);
    }
  }
  return 1;
}
