#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);				
}


//spi
#include "stm32f4xx_spi.h"
void initSpi(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);


    SPI_InitTypeDef SPI_InitStructure;
    SPI_I2S_DeInit(SPI1);
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_Cmd(SPI1, ENABLE);
}

u8 spi_GetByte() {
    u32 LIS302DLTimeout = 0x1000;
    /* Wait to receive a Byte */
    while (SPI_I2S_GetFlagStatus(SPI1,  SPI_FLAG_RXNE) == RESET) {
        if((LIS302DLTimeout--) == 0) return 0x00;
    }

    /* Return the Byte read from the SPI bus */
    return (u8)SPI_I2S_ReceiveData(SPI1);
}


u8 spi_SendByte(u8 byte) {
    u32 LIS302DLTimeout = 0x1000;

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET) {
        if((LIS302DLTimeout--) == 0) return 0x00;
    }

    /* Send a Byte through the SPI peripheral */
    SPI_I2S_SendData(SPI1, byte);

    return spi_GetByte();
}



int main(void)
{
usart2_init(115200);
inuart2line=inuart2len=0;


RCC_ClocksTypeDef RCC_ClocksStatus;

char c[64];
initSpi();

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

RCC_GetClocksFreq(&RCC_ClocksStatus);
print(USART2, "\nspi testik\n"); 

//@@@do some eeprom or so

#define MUXADDR  (0x70)
static uint8_t buf[10];
buf[0]=0x05;

    
print(USART2,"Enter text: ");
while(!inuart2line);
print(USART2,"Your input was: "); print(USART2,inuart2); print(USART2,"\n");
buf[1]=spi_SendByte(inuart2[0]);
inuart2line=inuart2len=0;
  }
}

void _sbrk(void) {}

