/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "misc.h"

#define USART_TX_BUFFER_SIZE    32 // кратен двум
#define USART_RX_BUFFER_SIZE    32 // кратен двум

enum usart_fifo_error
{
    USART_FIFO_ERROR_FRAME = 0x01,
    USART_FIFO_ERROR_OVERRUN = 0x02,
    USART_FIFO_ERROR_NOISE = 0x04,
    USART_FIFO_ERROR_BUFFER_OVERFLOW = 0x08,
    USART_FIFO_NO_DATA = 0x10
};

struct usart_fifo
{
	volatile uint8_t rx_last_error;
	volatile uint8_t rx_buffer[USART_RX_BUFFER_SIZE];
	volatile uint8_t rx_buffer_head;
	volatile uint8_t rx_buffer_tail;
	volatile uint8_t tx_buffer[USART_TX_BUFFER_SIZE];
	volatile uint8_t tx_buffer_head;
	volatile uint8_t tx_buffer_tail;
} usart1_fifo;


void USART1_IRQHandler(void)
{
	 int status;
	 uint8_t rx_data;
	 uint8_t rx_last_error;
	 uint8_t rx_head;
	 uint8_t tx_tail;
	 uint8_t tx_head;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
		status = USART1->SR;
		rx_data = USART1->DR;
		rx_last_error = 0;

		if (status & USART_SR_FE)
			rx_last_error |= USART_FIFO_ERROR_FRAME;

		if (status & USART_SR_ORE)
			rx_last_error |= USART_FIFO_ERROR_OVERRUN;

		if (status & USART_SR_NE)
			rx_last_error |= USART_FIFO_ERROR_NOISE;

		rx_head = (uint8_t)((usart1_fifo.rx_buffer_head + 1) & (uint8_t)(
				USART_RX_BUFFER_SIZE - 1));

		if (rx_head == usart1_fifo.rx_buffer_tail)
		{
			rx_last_error |= USART_FIFO_ERROR_BUFFER_OVERFLOW;
		}
		else
		{
			usart1_fifo.rx_buffer[rx_head] =  rx_data;
			usart1_fifo.rx_buffer_head =  rx_head;
		}

		usart1_fifo.rx_last_error = rx_last_error;

	}

	if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
	{

		tx_head = usart1_fifo.tx_buffer_head;
		tx_tail = usart1_fifo.tx_buffer_tail;

		if (tx_head != tx_tail++)
		{
			tx_tail &= USART_TX_BUFFER_SIZE - 1;

			usart1_fifo.tx_buffer_tail = tx_tail;

			USART1->DR =  usart1_fifo.tx_buffer[tx_tail];
		}
		else
		{
			USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
		}
	}
}

void usart1_fifo_transmit(uint8_t data)
{
	uint8_t tx_head;

	tx_head = (uint8_t)((usart1_fifo.tx_buffer_head + 1) & (uint8_t)(
			USART_TX_BUFFER_SIZE - 1));

	while (tx_head == usart1_fifo.tx_buffer_tail)
	{
	}

	usart1_fifo.tx_buffer[tx_head] =  data;
	usart1_fifo.tx_buffer_head = tx_head;

	USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
}

uint8_t usart1_fifo_receive(uint8_t * data)
{
	uint8_t rx_head;
	uint8_t rx_tail;

	rx_head = usart1_fifo.rx_buffer_head;

	if (rx_head == usart1_fifo.rx_buffer_tail)
		return USART_FIFO_NO_DATA;

	rx_tail = (uint8_t)((usart1_fifo.rx_buffer_tail + 1) & (uint8_t)(
			USART_RX_BUFFER_SIZE - 1));

	usart1_fifo.rx_buffer_tail = rx_tail;

	*data =  usart1_fifo.rx_buffer[rx_tail];

	return usart1_fifo.rx_last_error;
}

uint8_t COMGetchar()
{
	uint8_t rxd;
	while (usart1_fifo_receive(&rxd) & USART_FIFO_NO_DATA);
	return rxd;
}

uint8_t COMChekchar()
{
	uint8_t rxd;
	if (usart1_fifo_receive(&rxd) == USART_FIFO_NO_DATA) return 0;
	else return rxd;
}

void COMPutchar (uint8_t txd)
{
	usart1_fifo_transmit(txd);
}

void COMPutString (char * string)
		{
			while (*string != 0x00)
			{
				usart1_fifo_transmit(*string++);
			}
		}

void itoa(int val, int base,  char *bufstr) // число в строку
{
	uint8_t buf[32] = {0};
	int i = 30;
	int j;
	for(; val && i ; --i, val /= base)
		buf[i] = "0123456789abcdef"[val % base];
	i++; j=0;
	while (buf[i]!=0){ bufstr[j]=buf[i]; i++; j++;}
}
void COMPrintInt(int num)
{
	char bufnum[10]={0};
	itoa(num,10,bufnum);
	if (bufnum[0]==0) bufnum[0]=0x30;
	COMPutString (bufnum);
}

int atoi(const char* in_string)
{
        int i;
        int result;

        for(i = 0, result = 0; isdigit(in_string[i]); ++i) {
            result = result * 10 + in_string[i] - '0';
        }
        return(result);
    }

void ftoa(float f,  char *buf)
{
    int pos=0,ix,dp,num;
    if (f<0)
    {
        buf[pos++]='-';
        f = -f;
    }
    dp=0;
    while (f>=10.0)
    {
        f=f/10.0;
        dp++;
    }
    for (ix=1;ix<8;ix++)
    {
            num = f;
            f=f-num;
            if (num>9)
                buf[pos++]='#';
            else
                buf[pos++]='0'+num;
            if (dp==0) buf[pos++]='.';
            f=f*10.0;
            dp--;
    }
}

void COMPrintFloat(float num)
{
	char bufnum[10]={0};
	ftoa(num,bufnum);
	COMPutString (bufnum);
}

void InitUART(unsigned int speed)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	USART_InitTypeDef USART_InitStructure;

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA , ENABLE);// Тактирование
		/* Configure USART1 Tx (PA.09)  function push-pull */
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &GPIO_InitStructure);

		/* Configure USART1 Rx (PA.10) as input floating */
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* Configure the NVIC Preemption Priority Bits */
	//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

	/* Enable the USART1 Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	// инициализируем буфер
	usart1_fifo.rx_buffer_head = 0;
	usart1_fifo.rx_buffer_tail = 0;
	usart1_fifo.rx_last_error = 0;
	usart1_fifo.tx_buffer_head = 0;
	usart1_fifo.tx_buffer_tail = 0;

	// конфигурируем USART1
	USART_InitStructure.USART_BaudRate = speed;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

	USART_Init(USART1, &USART_InitStructure);

	// разрешаем прерывания по приёму
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

	// разрешаем работу модуля
	USART_Cmd(USART1, ENABLE);
}

void InitUART_map(unsigned int speed)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	USART_InitTypeDef USART_InitStructure;

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO , ENABLE);// Тактирование
		AFIO->MAPR |= AFIO_MAPR_USART1_REMAP;
		/* Configure USART1 Tx (PB.06) as alternate function push-pull */
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOB, &GPIO_InitStructure);

		/* Configure USART1 Rx (PB.07) as input floating */
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_Init(GPIOB, &GPIO_InitStructure);

	/* Configure the NVIC Preemption Priority Bits */
	//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

	/* Enable the USART1 Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	// инициализируем буфер
	usart1_fifo.rx_buffer_head = 0;
	usart1_fifo.rx_buffer_tail = 0;
	usart1_fifo.rx_last_error = 0;
	usart1_fifo.tx_buffer_head = 0;
	usart1_fifo.tx_buffer_tail = 0;

	// конфигурируем USART1
	USART_InitStructure.USART_BaudRate = speed;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

	USART_Init(USART1, &USART_InitStructure);

	// разрешаем прерывания по приёму
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

	// разрешаем работу модуля
	USART_Cmd(USART1, ENABLE);
}
/*
int main(void)
{
	InitUART(19200);
	COMPutString("Hello Word print this text!!!  ");
	COMPrintInt(12345);
	COMPutString("  ");
	COMPrintFloat(123.456);
	while (1)
	{
		COMPutchar(COMGetchar());
	}
	return 0;
}

*/
