#include "stm32f4_discovery.h"
#include "stm32f4xx_conf.h" // again, added because ST didn't put it here ?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

GPIO_InitTypeDef  GPIO_InitStructure;


void printsimple(USART_TypeDef* USARTx, char *t)
{
while(*t)
	{
	//assert_param(IS_USART_ALL_PERIPH(USARTx));
	//  assert_param(IS_USART_DATA(Data));
	while((USARTx->SR & USART_FLAG_TC)==0);
  	USARTx->DR = *t++;
	}
}

void Delay(__IO uint32_t nCount)
{
  while(nCount--)
  {
  }
}

#define INUART2MAX 128
volatile uint16_t inuart2len=0;
volatile inuart2line=0;
volatile char inuart2[INUART2MAX];

void USART2_IRQHandler(void){
if(USART_GetITStatus(USART2, USART_IT_RXNE) ){
	char c = USART2->DR; 
	if(c=='\r') c='\n';
	while((USART2->SR & USART_FLAG_TC)==0); USART2->DR = c; //echo
	if(!inuart2line) 
		{
		inuart2[inuart2len++] = c;
		if(c=='\n' || inuart2len == INUART2MAX) 
			{inuart2[inuart2len-1] = 0; inuart2line=inuart2len; 
			}
		}
}
}

#define MAXUSART2OUT 256
static char outuart2[MAXUSART2OUT];
static DMA_InitTypeDef DMA_InitStruct;
static uint8_t uart2virgin=1;

void print(USART_TypeDef* USARTx, char *t)
{
if(*t == 0) return;
while((USART2->SR & USART_FLAG_TC)==0); //wait for non-dma tx completion
if(!uart2virgin) while(DMA_GetFlagStatus(DMA1_Stream6, DMA_FLAG_TCIF6)==0); //wait for dma tx completion
uint16_t len=0;
while(*t) {outuart2[len++]= *t++; if(len==MAXUSART2OUT-1) {outuart2[len++]=0; break;}}

DMA_InitStruct.DMA_BufferSize = DMA1_Stream6->NDTR = len;
DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_TCIF6); //clear transfer complete to allow next one
DMA_Cmd(DMA1_Stream6, ENABLE);
uart2virgin=0;
}


void scan(USART_TypeDef* USARTx, char *string)
{
char c;
        do      {
                do {
			while((USARTx->SR & USART_FLAG_RXNE)==0);
                        c = USARTx->DR;
                        } while ((USARTx->SR & USART_FLAG_FE)==1);
                *string++ = c;
		while((USARTx->SR & USART_FLAG_TC)==0);
		USARTx->DR = c;
                } while ( c != '\r' );
	while((USARTx->SR & USART_FLAG_TC)==0);
	USARTx->DR = '\n';
        string[-1]=0;
}


usart2_init(uint32_t baud)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;

//RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //for USART1 and USART6
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //for USART2, USART3, UART4 or UART5

/* GPIOA clock enable */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

/* GPIOA Configuration:  USART2 TX on PA2, RX on PA3 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
	GPIO_Init(GPIOA, &GPIO_InitStructure); 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA, &GPIO_InitStructure); 


/* Connect USART2 pins to AF */ 
	// TX = PA2, RX = PA3
 	GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
 	GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
	USART_InitStructure.USART_BaudRate = baud;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx |USART_Mode_Tx;
	USART_Init(USART2, &USART_InitStructure);

	USART_Cmd(USART2, ENABLE); // enable USART2

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

//DMA usart2 TX = stream 6 channel 4 
  DMA_StructInit(&DMA_InitStruct);
  DMA_InitStruct.DMA_Channel = DMA_Channel_4;
  DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART2->DR);
  DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)outuart2;
  DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  DMA_InitStruct.DMA_BufferSize = 0;
  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
  DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA1_Stream6, &DMA_InitStruct);
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);

//for rx
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); 
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;		 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;		
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	
	NVIC_Init(&NVIC_InitStructure);				
}




int main(void)
{
usart2_init(115200);

RCC_ClocksTypeDef RCC_ClocksStatus;

char c[64];

//USART_SetPrescaler(USART2,1);
  while (1)
  {

RCC_GetClocksFreq(&RCC_ClocksStatus);
  print(USART2, "uart testik\n"); 
sprintf(c,"HSE_VALUE %u HSI_VALUE %u\n",HSE_VALUE,HSI_VALUE); print(USART2,c);

sprintf(c,"RCC->CFGR & RCC_CFGR_SWS %d\n",RCC->CFGR & RCC_CFGR_SWS); print(USART2,c);
uint32_t pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
uint32_t pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
uint32_t plln = (RCC->PLLCFGR & RCC_PLLCFGR_PLLN)>>6;
uint32_t pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
uint32_t pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
sprintf(c,"pllsource %u\n",pllsource); print(USART2,c);
sprintf(c,"pllm %u plln %u pllp %u\n",pllm,plln,pllp); print(USART2,c);
sprintf(c,"pllvco %u\n",pllvco); print(USART2,c);
sprintf(c,"FINAL = pllvco/pllp %u\n",pllvco/pllp); print(USART2,c);

sprintf(c,"SYSCLK_Frequency %u\n",RCC_ClocksStatus.SYSCLK_Frequency); print(USART2,c);
sprintf(c,"HCLK_Frequency %u\n",RCC_ClocksStatus.HCLK_Frequency); print(USART2,c);
sprintf(c,"PCLK1_Frequency %u\n",RCC_ClocksStatus.PCLK1_Frequency); print(USART2,c);
sprintf(c,"PCLK2_Frequency %u\n",RCC_ClocksStatus.PCLK2_Frequency); print(USART2,c);
    
print(USART2,"Enter text: ");
while(!inuart2line);
print(USART2,"Your input was: "); print(USART2,inuart2); print(USART2,"\n");
inuart2line=inuart2len=0;
  }
}

void _sbrk(void) {}

